『 再看.NET7』让json序列化体现多态

从System.Text.Json诞生,就在努力增加功能和提升性能,在.NET7中,又带来了多态的适配。

下面是一个父类Customer,两个子类,WechatCustomer和LineCustomer。.

public class Customer{    public string Name { get; set; }    public string Address { get; set; }    public string City { get; set; }    public string Region { get; set; }    public string PostalCode { get; set; }    public string EMail { get; set; }    public string Tel { get; set; }}
public class WechatCustomer : Customer{    public string? WechatNo { get; set; }}public class LineCustomer : Customer{    public string? LineNo { get; set; }}

分别用一个打印方法PrintCustomer输出两个子类对象。

var wechatCustomer = new WechatCustomer{    Name = "张三",    City = "东京",    Region = "中央区",    Address = "1-56-326",    PostalCode = "3000235",    EMail = "abcde@gmail.com",    Tel = "08-9563-2356",    WechatNo = "wechat_gsw" };var lineCustomer = new LineCustomer{    Name = "张三",    City = "东京",    Region = "中央区",    Address = "1-56-326",    PostalCode = "3000235",    EMail = "abcde@gmail.com",    Tel = "08-9563-2356",    LineNo = "line_gsw"};//共用打印方法void PrintCustomer(Customer customer){    var options = new JsonSerializerOptions    {        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,        WriteIndented = true    };    var json = JsonSerializer.Serialize<Customer>(customer, options);    Console.WriteLine(json);}
PrintCustomer(wechatCustomer);PrintCustomer(lineCustomer);

输出结果是:

{  "Name": "张三",  "Address": "1-56-326",  "City": "东京",  "Region": "中央区",  "PostalCode": "3000235",  "EMail": "abcde@gmail.com",  "Tel": "08-9563-2356"}{  "Name": "张三",  "Address": "1-56-326",  "City": "东京",  "Region": "中央区",  "PostalCode": "3000235",  "EMail": "abcde@gmail.com",  "Tel": "08-9563-2356"}

现在丢失了子类的属性WechatNo和LineNo,在.NET7中,可以通过两种方式来保证不丢失这种多态产生的新的属性:特性和自定义类型信息解析器。

特性:

[JsonPolymorphic(TypeDiscriminatorPropertyName = "CustomerType")][JsonDerivedType(typeof(WechatCustomer), typeDiscriminator: "wechatCustomer")][JsonDerivedType(typeof(LineCustomer), typeDiscriminator: "lineCustomer")]public class Customer{……}

通过给父类Customer添加特性,来达到json化的效果。再次输出如下:

{  "CustomerType": "wechatCustomer",  "WechatNo": "wechat_gsw",  "Name": "张三",  "Address": "1-56-326",  "City": "东京",  "Region": "中央区",  "PostalCode": "3000235",  "EMail": "abcde@gmail.com",  "Tel": "08-9563-2356"}{  "CustomerType": "lineCustomer",  "LineNo": "line_gsw",  "Name": "张三",  "Address": "1-56-326",  "City": "东京",  "Region": "中央区",  "PostalCode": "3000235",  "EMail": "abcde@gmail.com",  "Tel": "08-9563-2356"}

可以看到,JsonPolymorphic特性是定义一个标注子类名称的属性customerType,而JsonDerivedType是定义两个子类的特性。

自定义类型信息解析器:

首先定义自定义类型信息解析器class,可以看出,他的作用与上面的特性是一样的。

public class PolymorphicTypeResolver : DefaultJsonTypeInfoResolver{    public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)    {        JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);
        Type basePointType = typeof(Customer);        if (jsonTypeInfo.Type == basePointType)        {            jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions            {                TypeDiscriminatorPropertyName = "CustomerType",                DerivedTypes =                {                    new JsonDerivedType(typeof(WechatCustomer), "wechatCustomer"),                    new JsonDerivedType(typeof(LineCustomer), "lineCustomer")                }            };        }        return jsonTypeInfo;    }}

这个时候,Customer上的特性就可以没有了,只要在PrintCustomer方法中给options加个属性即可。

void PrintCustomer(Customer customer){    var options = new JsonSerializerOptions    {        TypeInfoResolver = new PolymorphicTypeResolver(),        Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,        WriteIndented = true    };    var json = JsonSerializer.Serialize<Customer>(customer, options);    Console.WriteLine(json);}

输出结果与特性方式是一样的。这里不再赘述。

上面两种方式,也可以把对应的json字符串反序列化回来。