後にデシリアライズ関連するgetおよびsetメソッドを持つ型階層の各レベルで、民間分野:
public class DeclaredFieldJsonConverter<T> : JsonConverter where T: new()
{
const string basePropertyName = "base";
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jObj = JObject.Load(reader);
existingValue = existingValue ?? new T();
var type = existingValue.GetType();
while (jObj != null && type != null)
{
var basejObj = jObj.ExtractPropertyValue(basePropertyName) as JObject;
JsonObjectContract contract = (JsonObjectContract)DeclaredFieldContractResolver.Instance.ResolveContract(type);
foreach (var jProperty in jObj.Properties())
{
var property = contract.Properties.GetClosestMatchProperty(jProperty.Name);
if (property == null)
continue;
var value = jProperty.Value.ToObject(property.PropertyType, serializer);
property.ValueProvider.SetValue(existingValue, value);
}
type = type.BaseType;
jObj = basejObj;
}
return existingValue;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
WriteJson(writer, value, value.GetType(), serializer);
}
void WriteJson(JsonWriter writer, object value, Type type, JsonSerializer serializer)
{
JsonObjectContract contract = (JsonObjectContract)DeclaredFieldContractResolver.Instance.ResolveContract(type);
writer.WriteStartObject();
foreach (var property in contract.Properties.Where(p => !p.Ignored))
{
writer.WritePropertyName(property.PropertyName);
serializer.Serialize(writer, property.ValueProvider.GetValue(value));
}
var baseType = type.BaseType;
if (baseType != null && baseType != typeof(object))
{
writer.WritePropertyName(basePropertyName);
WriteJson(writer, value, baseType, serializer);
}
writer.WriteEndObject();
}
}
public static class JsonExtensions
{
public static JToken ExtractPropertyValue(this JObject obj, string name)
{
if (obj == null)
return null;
var property = obj.Property(name);
if (property == null)
return null;
var value = property.Value;
property.Remove();
property.Value = null;
return value;
}
}
class DeclaredFieldContractResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
// See also https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
static DeclaredFieldContractResolver instance;
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static DeclaredFieldContractResolver() { instance = new DeclaredFieldContractResolver(); }
public static DeclaredFieldContractResolver Instance { get { return instance; } }
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var fields = objectType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(f => !f.IsNotSerialized);
return fields.Cast<MemberInfo>().ToList();
}
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.MemberSerialization = MemberSerialization.Fields;
return contract;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, MemberSerialization.Fields);
}
}
が続いて、次のようにそれを使用する:
var demo = new MyDemo();
var json = JsonConvert.SerializeObject(demo, new DeclaredFieldJsonConverter<MyDemo>());
をサンプルfiddle。
型階層内のどこにでもbase
という名前のフィールドがあると、重複したJSONプロパティ名が書き込まれ、デシリアライズ時に情報が失われる可能性があることに注意してください。これをチェックして何らかの方法で処理したいと思うかもしれません。
出典
2016-12-15 19:09:22
dbc
次に、カスタムシリアライザを作成するか、フィールドを非プライベートにする必要があります。最良の解決策は、プログラムで使用するクラスをシリアライズしないことですが、シリアライゼーションに必要な構造体を持つ別々のシリアライゼーションに適したクラスを作成し、次に前後にマップすることです。これは、あなたが今のところ持っているような問題を避けるために、あるいはあなたが使用しているクラスへの直列化調整を行うためです。 –