JsonSubTypes + Newtonsoft.Json 实现json 数据多态处理

在java 开发中jackson 的多太json 处理是一个很强大的功能,可以解决不少有意思的问题(比如动态方法执行,基于用户请求的json 数据,查找对应的消息处理器,不用单独进行判断处理),.net 也有一个扩展包JsonSubTypes 结合Newtonsoft.Json 可以实现类似jackson 的能力,以下是一个简单说明

基于JsonConverter模式的

此模式适合子类型确定的

  • Animal
[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }

    public virtual string DoMessage()
    {
        return $"The default says {Sound} and is a {Color}";
    }
}
  • Dog

public class Dog:Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }

    public override String DoMessage()
    {
        return $"The dog says {Sound} and is a {Breed}";
    }
}
  • Cat
public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }

    public override string DoMessage()
    {
        return $"The cat says {Sound} and is declawed: {Declawed}";
    }

}
  • 序列化集成
using jsonapp;
using Newtonsoft.Json;

var cat = new Cat()
{
    Declawed= true,
    Color = "Red"
};

var dog = new Dog()
{
    Breed = "demoapp",
    Color = "black"
};

var animalStrv1 = JsonConvert.SerializeObject(cat);

var animalStrv2 = JsonConvert.SerializeObject(dog);

Console.WriteLine(animalStrv1);
Console.WriteLine(animalStrv2);

var animalv1 = JsonConvert.DeserializeObject<Animal>(animalStrv1);

var animalv2 = JsonConvert.DeserializeObject<Animal>(animalStrv2);

Console.WriteLine(animalv1?.DoMessage());

Console.WriteLine(animalv2?.DoMessage());
  • 效果

可以看到类方法可以正确的被调用,而不是Animal 的默认方法

{"Sound":"Meow","Declawed":true,"Color":"Red"}
{"Sound":"Bark","Breed":"demoapp","Color":"black"}
The cat says Meow and is declawed: True
The dog says Bark and is a demoapp

手工注册类型模式

此模式动态能力就比较强了

  • Animal

去掉以前的属性标记

//
// [JsonConverter(typeof(JsonSubtypes), "Sound")]
// [JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
// [JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }

    public virtual string DoMessage()
    {
        return $"The default says {Sound} and is a {Color}";
    }
}
  • 注册类型
using jsonapp;
using JsonSubTypes;
using Newtonsoft.Json;

// 配置类型,此处我使用了字符串
var settings = new JsonSerializerSettings();
settings.Converters.Add(JsonSubtypesConverterBuilder
    .Of(typeof(Animal), "Type") // type property is only defined here
    .RegisterSubtype(typeof(Cat), "Cat")
    .RegisterSubtype(typeof(Dog), "Dog")
    .SerializeDiscriminatorProperty() // ask to serialize the type property
    .Build());

var cat = new Cat()
{
    Declawed= true,
    Color = "Red"
};

var dog = new Dog()
{
    Breed = "demoapp",
    Color = "black"
};
// 序列化使用settings
var animalStrv1 = JsonConvert.SerializeObject(cat,settings);

var animalStrv2 = JsonConvert.SerializeObject(dog,settings);

Console.WriteLine(animalStrv1);
Console.WriteLine(animalStrv2);

// 反序列化也需要使用settings
var animalv1 = JsonConvert.DeserializeObject<Animal>(animalStrv1,settings);

var animalv2 = JsonConvert.DeserializeObject<Animal>(animalStrv2,settings);

Console.WriteLine(animalv1?.DoMessage());

Console.WriteLine(animalv2?.DoMessage());
  • 效果

可以看到会自动多了一个type 字段

{"Type":"Cat","Sound":"Meow","Declawed":true,"Color":"Red"}
{"Type":"Dog","Sound":"Bark","Breed":"demoapp","Color":"black"}
The cat says Meow and is declawed: True
The dog says Bark and is a demoapp

说明

通过JsonSubTypes 对于.net 应该设计,就可以使用类似java jackson 模式了,是的一个很不错的包,可以方便的实现代码解耦

参考资料

https://github.com/manuc66/JsonSubTypes

https://github.com/JamesNK/Newtonsoft.Json

https://www.newtonsoft.com/json

https://manuc66.github.io/JsonSubTypes/

https://www.baeldung.com/java-jackson-polymorphic-deserialization

posted on 2025-07-21 08:00  荣锋亮  阅读(38)  评论(0)    收藏  举报

导航