JSON.net TypeNameHandling : 自定义自动

JSON.net TypeNameHandling : customize Auto

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

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

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

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

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

的 javascript 代码

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

说这是你的 class:

[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 });

会抛出

Unhandled exception. Newtonsoft.Json.JsonSerializationException: Could not create an instance of type ISomeInterfaceA. Type is an interface or abstract class and cannot be instantiated. Path 'MyB.Banana', line 1, position 69.