仅针对 json.NET 的某些字段的自定义反序列化程序
Custom deserializer only for some fields with json.NET
我正在尝试反序列化一些 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
}
]
}
我想找到一种方法来为某些字段定义自定义反序列化。
在下面的代码中,我将需要注意的字段(自定义处理)和可以以某种方式自动完成的字段分开。
是否可以自动反序列化 "normal" 字段? (不需要任何特定的自定义处理)
[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);
}
}
一种可能的方法是创建代理 属性 以正确地序列化和反序列化。通过使用 ScriptIgnoreAttribute (also possible is the JsonIgnoreAttribute) 真正的 属性 不会被序列化。这是一个例子:
[ScriptIgnore]
public int RealProperty { get; set; }
public string RealPropertyProxy
{
get
{
return SerializeRealProperty(RealProperty);
}
set
{
RealProperty = DeserializeRealProperty(value);
}
}
结果是只有代理按照您定义的方式进行序列化(基于真实 属性 的值)。只需以特殊方式修改需要序列化的属性即可,无需实现特殊的JsonConverter
.
既然你是用 Json.NET 属性注释你的类型,一个更简单的解决方案似乎是使用 [JsonConverter(Type)]
or [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
and cannot add Json.NET attributes to your type), you can use 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;
}
}
我正在尝试反序列化一些 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
}
]
}
我想找到一种方法来为某些字段定义自定义反序列化。
在下面的代码中,我将需要注意的字段(自定义处理)和可以以某种方式自动完成的字段分开。
是否可以自动反序列化 "normal" 字段? (不需要任何特定的自定义处理)
[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);
}
}
一种可能的方法是创建代理 属性 以正确地序列化和反序列化。通过使用 ScriptIgnoreAttribute (also possible is the JsonIgnoreAttribute) 真正的 属性 不会被序列化。这是一个例子:
[ScriptIgnore]
public int RealProperty { get; set; }
public string RealPropertyProxy
{
get
{
return SerializeRealProperty(RealProperty);
}
set
{
RealProperty = DeserializeRealProperty(value);
}
}
结果是只有代理按照您定义的方式进行序列化(基于真实 属性 的值)。只需以特殊方式修改需要序列化的属性即可,无需实现特殊的JsonConverter
.
既然你是用 Json.NET 属性注释你的类型,一个更简单的解决方案似乎是使用 [JsonConverter(Type)]
or [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
and cannot add Json.NET attributes to your type), you can use 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;
}
}