首页 > 解决方案 > JSON.net TypeNameHandling : 自定义 Auto

问题描述

我正在使用 JSON.net 序列化类并使用 TypeNameHandling=Auto 插入“$type”注释。为了这个例子,假设这是我的课:

[JsonObject]
public class MyClass
{
    [JsonProperty]
    public ISomeInterfaceA MyA { get; set; }

    [JsonProperty]
    public ISomeInterfaceB MyB { get; set; }
}

这样,“MyA”和“MyB”都会收到“$type”属性。不幸的是,我处于一个奇怪的情况,我需要“MyA”来拥有“$type”,但“MyB”不应该“$type”。json.net 是否有任何东西可以让我自定义 TypeNameHandling.Auto 的行为,以便我可以手动选择我想要的位置?

至于我为什么要做这样的事情,复杂的原因是我正在从另一个遗留序列化器迁移到 JSON.net,并且我试图最小化旧序列化器和新序列化器之间的差异,以避免重写大大量使用 JSON 的 JavaScript 代码。

标签: c#json.net

解决方案


您可以使用自定义转换器来实现此目的。

说这是你的课:

[JsonObject]
public class MyClass {
    [JsonProperty]
    public ISomeInterfaceA MyA { get; set; }
    
    [JsonProperty]
    [JsonConverter(typeof(NoTypeConverter))]
    public ISomeInterfaceA MyB { get; set; }
}

我们需要一个自定义转换器:

public class NoTypeConverter: JsonConverter<ISomeInterfaceA> {
    public override ISomeInterfaceA ReadJson(JsonReader reader, Type objectType, ISomeInterfaceA existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, ISomeInterfaceA value, JsonSerializer serializer)
    {
       // Note: this is not the most efficient way to do this, but you can customise this how you see fit.
        writer.WriteRawValue(JsonConvert.SerializeObject(value));
    }

    public override bool CanWrite => true;

    public override bool CanRead => false;
}

然后:

var stuff = JsonConvert.SerializeObject(new MyClass 
{ MyA = new A { Banana = "cheese" }, 
  MyB = new A { Banana = "notype"} },
new JsonSerializerSettings{ TypeNameHandling=TypeNameHandling.Auto });
                                                        
Console.WriteLine(stuff); // {"MyA":{"$type":"whatever, here","Banana":"cheese"},"MyB":{"Banana":"notype"}}

但是请注意,您不能以这种方式将 BACK 反序列化为您的类型,因为缺少类型信息MyB

var x = JsonConvert.DeserializeObject<MyClass>(stuff, 
    new JsonSerializerSettings{ TypeNameHandling=TypeNameHandling.Auto });

那会抛出

未处理的异常。Newtonsoft.Json.JsonSerializationException:无法创建 ISomeInterfaceA 类型的实例。类型是接口或抽象类,不能实例化。路径“MyB.Banana”,第 1 行,位置 69。


推荐阅读