在JsonConverter的ReadJson方法中使用的existingValue参数是什么?

时间:2014-06-22 02:27:01

标签: json.net

创建自定义Json转换器时,需要覆盖的方法之一是:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)

什么是" existingValue"参数用于?变量名称是什么" existingValue"在这种情况下意味着什么?

3 个答案:

答案 0 :(得分:18)

简单地说,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属性Value1Value2,两者都使用此转换器。 Value1在构造函数中分配了默认值42,而Value2的默认值通常为零。

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参数,并且大多数时候它的值将为null或0。你可以放心地忽略它。

答案 1 :(得分:5)

我认为这个主要用例是用于填充&#34;现有属性,其值可变但不可自行写入。例如:

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属性。

答案 2 :(得分:2)

existingValue是一个可选值(检查为null),可以通过其他方法或基本方法进行部分反序列化。这通常为null,但在设置具有JsonConverter的属性时可能为非null。

我还没有看到任何使用此值的ReadJson实现(但这并不意味着没有任何内容)。