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.
我正在使用 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.