我正在尝试反序列化一些 JSON:
{
"a":1,
"b":25,
"c":"1-7",
"obj1":{
"a1":10,
"b1":45,
"c1":60
},
"obj2":[
{
"a2":100,
"b2":15,
"c2":50
},
{
"e2":"1,2,5-7",
"f2":"1,3-5",
"a2":25
}
]
}
我想找到一种方法来仅为某些字段定义自定义反序列化。
在下面的代码中,我将需要注意的字段(自定义处理)和可以以某种方式自动完成的字段分开。
是否可以自动反序列化"正常"字段?(不需要任何特定的自定义处理)
[JsonConverter(typeof(ConfigurationSerializer))]
public class Configuration
{
public int a { get; set; }
public int b { get; set; }
public Obj1 obj1 { get; set; }
public int[] c { get; set; }
public IList<Obj2> obj2 { get; set; }
}
public class ConfigurationSerializer : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jsonObject = JObject.Load(reader);
Configuration configuration = new Configuration();
// I would like this part to be automatic as I just repeat the default
// In the real case, I have many fields here!
configuration.a = (int)jsonObject["a"];
configuration.b = (int)jsonObject["b"];
configuration.obj1 = jsonObject["obj1"].ToObject<Obj1>();
// I created the JsonConverter for those 2 properties
configuration.c = myCustomProcessMethod(jsonObject["c"]);
configuration.obj2 = myCustomProcessMethod2(jsonObject["obj2"].ToObject<ValletConfiguration>());
return configuration;
}
public override bool CanConvert(Type objectType)
{
return typeof(Configuration).IsAssignableFrom(objectType);
}
}
由于无论如何您都使用 Json.NET 属性注释您的类型,因此更简单的解决方案似乎是使用 [JsonConverter(Type)]
或 [JsonProperty(ItemConverterType = Type)]
将转换器放在相关属性上:
public class Configuration
{
public int a { get; set; }
public int b { get; set; }
public Obj1 obj1 { get; set; }
// Converts the entire list to a compressed string
[JsonConverter(typeof(IntListConverter))]
public int[] c { get; set; }
// Converts each Obj2 item individually
[JsonProperty(ItemConverterType = typeof(Obj2Converter))]
public IList<Obj2> obj2 { get; set; }
}
但是,如果您需要在Configuration
上保留转换器(或者实际上正在将转换器添加到JsonSerializerSettings.Converters
并且无法向类型添加 Json.NET 属性),则可以使用 JsonSerializer.Populate()
填充标准属性,只要您首先从JObject
中删除自定义属性:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var jsonObject = JObject.Load(reader);
var configuration = (existingValue as Configuration ?? new Configuration());
// I created the JsonConverter for those 2 properties
configuration.c = myCustomProcessMethod(jsonObject["c"].RemoveFromLowestPossibleParent());
configuration.obj2 = myCustomProcessMethod2(jsonObject["obj2"].RemoveFromLowestPossibleParent().ToObject<ValletConfiguration>());
// Populate the remaining standard properties
using (var subReader = jsonObject.CreateReader())
{
serializer.Populate(subReader, configuration);
}
return configuration;
}
使用扩展方法:
public static class JsonExtensions
{
public static JToken RemoveFromLowestPossibleParent(this JToken node)
{
if (node == null)
return null;
var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
if (contained != null)
contained.Remove();
// Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
if (node.Parent is JProperty)
((JProperty)node.Parent).Value = null;
return node;
}
}
一种可能的方法是创建一个代理属性来正确序列化和反序列化。通过使用 ScriptIgnoreAttribute(也可能是 JsonIgnoreAttribute),真实属性不会被序列化。下面是一个示例:
[ScriptIgnore]
public int RealProperty { get; set; }
public string RealPropertyProxy
{
get
{
return SerializeRealProperty(RealProperty);
}
set
{
RealProperty = DeserializeRealProperty(value);
}
}
结果是,只有代理按照您定义它的方式(基于不动产的值)进行序列化。只需修改需要以特殊方式序列化的属性,就不需要实现特殊的JsonConverter
。