在没有 [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);
}
}
}
我必须序列化派生 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);
}
}
}