在没有 [DataContract] 的情况下序列化基 class 的私有字段

Serilalize private field of base class without [DataContract]

我必须序列化派生 class,但我需要它包含的所有数据(包括私有字段和基本 class 字段)。

我想使用 [Datacontract] 如下。

using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;

namespace ConsoleApplication1
{
    class Program
    {
        [DataContract]
        class Base
        {
            public Base(int fieldValue)
            {
                _field = fieldValue;
            }

            [DataMember]
            private int _field;
        }

        class Derived : Base
        {
            public Derived(int fieldValue) : base(fieldValue)
            {
            }
        }
    
        public static void Main(string[] args)
        {
            var derived = new Derived(10);
            var serialized = JsonConvert.SerializeObject(derived);
            Console.WriteLine(serialized);
        }
    }
}

但是遗留的class太多需要修改,所以我跟着the question写了Contract resolver

public class MyContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = type
            .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
            .Where(p => p.CanRead && p.CanWrite)
            .Select(p => base.CreateProperty(p, memberSerialization))
            .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(f => base.CreateProperty(f, memberSerialization)))
            .Distinct(JsonPropertyComparer.Instance)
            .ToList();

        foreach (var property in properties)
        {
            var ignored = ShouldPropertyBeIgnored(property);

            property.Ignored = ignored;
            property.Readable = !ignored;
            property.Writable = !ignored;
        }
            
        return properties;
    }

    // Actualy, contains some logic
    private bool ShouldPropertyBeIgnored(JsonProperty property) => false;
}

遗憾的是,它不序列化基本类型的属性

user2864740 所述,基类型的私有属性不会被继承(并且它们不是多态的),因此 currentType.GetProperties(..) 不包括它们。

因此,我将 .BaseType 迭代为 there

它解决了我的问题。可重现的代码示例如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace DerivedSerialization
{
    internal class MyContractResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = GetJsonProperties(type, memberSerialization);
            foreach (var property in properties)
            {
                property.Ignored = false;
                property.Readable = true;
                property.Writable = true;
            }
            return properties;
        }

        private IList<JsonProperty> GetJsonProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = type
                .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(p => p.CanRead && p.CanWrite)
                .Select(p => base.CreateProperty(p, memberSerialization))
                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Select(f => base.CreateProperty(f, memberSerialization)));

            if (type.BaseType == null)
                return properties.Distinct(new JsonPropertyComparer()).ToList();

            return properties.Union(GetJsonProperties(type.BaseType, memberSerialization))
                .Distinct(new JsonPropertyComparer())
                .ToList();
        }
    }

    #region JsonPropertyComparer
    
    internal class JsonPropertyComparer : IEqualityComparer<JsonProperty>
    {
        public bool Equals(JsonProperty left, JsonProperty right)
        {
            if (ReferenceEquals(left, right)) return true;

            if (left == null || right == null) return false;

            return left.PropertyName?.Equals(right.PropertyName) ?? right.PropertyName == null;
        }

        public int GetHashCode(JsonProperty obj)
        {
            return obj.PropertyName?.GetHashCode() ?? 0;
        }
    }
    
    #endregion

    internal class Program
    {
        class Base
        {
            public Base(int fieldValue)
            {
                _field = fieldValue;
            }
            
            private int _field;
        }

        class Derived : Base
        {
            public Derived(int fieldValue) : base(fieldValue)
            {
            }
        }
    
        public static void Main(string[] args)
        {
            var derived = new Derived(10);
            var jsonSettings = new JsonSerializerSettings { ContractResolver = new MyContractResolver() };
            var serialized = JsonConvert.SerializeObject(derived, jsonSettings);
            Console.WriteLine(serialized);
        }
    }
}