创建自定义Json转换器时,需要重写的方法之一是:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
"existingValue"参数的作用是什么?在这个上下文中,变量名"existingValue"是什么意思?
简单地说,existingValue
参数为您提供对象的现有值或默认值,该值最终将被ReadJson
方法返回的值所替换。这使得ReadJson
方法有机会在确定返回内容时评估现有值。例如,如果需要,该方法可以决定保留默认值,或者以某种方式将其与来自读取器的反序列化值组合在一起。
考虑下面的例子。该转换器将从JSON中反序列化一个整数值,并返回该值与被反序列化到的字段的现有值的和。
class AdditiveIntConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(int));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
return (int)existingValue + token.ToObject<int>();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
现在假设我们有一个类Foo
,它有两个int
属性,Value1
和Value2
,它们都使用这个转换器。Value1
在构造函数中被赋值为默认值42
,而Value2
的默认值通常为0。
class Foo
{
[JsonConverter(typeof(AdditiveIntConverter))]
public int Value1 { get; set; }
[JsonConverter(typeof(AdditiveIntConverter))]
public int Value2 { get; set; }
public Foo()
{
Value1 = 42;
}
}
如果我们将一些数据反序列化到这个类中…
class Program
{
static void Main(string[] args)
{
string json = @"{ ""Value1"" : 18, ""Value2"" : 33 }";
Foo foo = JsonConvert.DeserializeObject<Foo>(json);
Console.WriteLine("Value1: " + foo.Value1);
Console.WriteLine("Value2: " + foo.Value2);
}
}
…我们得到以下结果:
Value1: 60
Value2: 33
当然,这只是一个人为的例子。在实践中,在实现JsonConverter时不太需要使用existingValue
参数,大多数情况下它的值要么为空,要么为零。
我认为这样做的主要用例是"填充"现有的属性,这些属性的值是可变的,但它们本身是不可写的。例如:
public class A {
private readonly List<int> b = new List<int> { 1 };
public List<int> B { get { return this.b; } }
}
JsonConvert.DeserializeObject<A>("{ B: [2] }").Dump(); // B has both 1 and 2!
现在,假设我们有一个自定义类型的只读属性,而不是名为B的列表:
// try this code in LinqPad!
void Main()
{
JsonConvert.DeserializeObject<A>("{ C: { Y: 5 } }").Dump();
}
// Define other methods and classes here
public class A {
private readonly C c = new C { X = 1 };
public C C { get { return this.c; } }
}
[JsonConverter(typeof(CJsonConverter))]
public class C {
public int X { get; set; }
public int Y { get; set; }
}
public class CJsonConverter : JsonConverter {
public override bool CanConvert(Type objectType)
{
return objectType == typeof(C);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// VERSION 1: don't use existingValue
//var value = new C();
// VERSION 2: use existingValue
var value = (C)existingValue ?? new C();
// populate value
var dict = serializer.Deserialize<Dictionary<string, int>>(reader);
if (dict.ContainsKey("X")) { value.X = dict["X"]; }
if (dict.ContainsKey("Y")) { value.Y = dict["Y"]; }
return value;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
注意,代码显示了编写转换器的两种方法。一个使用现有的价值,另一个没有。如果我们使用现有值,我们将"{ C: { Y: 5 } }"
反序列化为:{ C: { X: 1, Y:5 } }
,从而保留X = 1的默认值并填充只读属性C。另一方面,如果我们不使用现有值并且总是让转换器创建一个新的C,那么我们根本无法填充只读C属性。
existingValue
是一个可选值(检查是否为null),可以被其他方法或基方法部分反序列化。这通常为null,但在设置具有JsonConverter
的属性时可能为非null。
我还没有看到任何ReadJson
实现使用这个值(但这并不意味着没有任何)。