在 C# 中反序列化之前是否有检查对象的类类型?

Con*_*nor 3 c# serialization json json-deserialization json-serialization

例如,我有几种类型的汽车正在序列化为 .car 文件(这是一个学校项目)。我有三种不同的车型:福特、雷克萨斯和道奇。我可以很好地拯救他们。但是根据我的程序的当前架构,当我反序列化时,我需要在反序列化之前知道类型。例如我这样序列化:

if (CurrentCar.GetType() == typeof(Ford))
{
   var JSON_CAR = JsonSerializer.Serialize((Ford)CurrentCar);
   writer.Write(JSON_CAR);
}
Run Code Online (Sandbox Code Playgroud)

当我反序列化时,我需要在反序列化之前知道类型:

CurrentCar = JsonSerializer.Deserialize<???>(reader.ReadString());
Run Code Online (Sandbox Code Playgroud)

我怎样才能实现这个目标?谢谢。

Ibr*_*eda 6

更新.NET 7

现在最新、最好的 .NET 7 提供了对多态序列化和反序列化的全面支持。

您只需要为基类添加一些元数据就可以了

[JsonPolymorphic(TypeDiscriminatorPropertyName = "$CarManufacturer")]
[JsonDerivedType(typeof(Ford), "Ford")]
[JsonDerivedType(typeof(BMW),"BMW")]
class Car
{
    public string Name { get; set; }
}

class Ford : Car
{
    public string OnlyFord { get; set; }
}

class BMW : Car
{
    public string OnlyBMW { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

连载

Car CurrentCar = new Ford { Name = "Foard Car", OnlyFord = "spacific feature in Ford Cars" };
string json = JsonSerializer.Serialize(CurrentCar);
Console.WriteLine(json);
Run Code Online (Sandbox Code Playgroud)

这将生成以下 json

{"$CarManufacturer":"Ford","OnlyFord":"spacific feature in Ford Cars","Name":"Foard Car"}
Run Code Online (Sandbox Code Playgroud)

反序列化

var car = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(car is Ford); // true
Run Code Online (Sandbox Code Playgroud)

旧答案(.NET 6 或更早版本)

如果您不知道汽车的确切类型,您的 Json 应该包含保存其类型的属性

var car = JsonSerializer.Deserialize<Car>(json);
Console.WriteLine(car is Ford); // true
Run Code Online (Sandbox Code Playgroud)

您可以将此属性手动添加到您的类中

{
  "CarManufacturer" : "FORD"
}
Run Code Online (Sandbox Code Playgroud)

你可以将其序列化如下

enum CarManufacturer
{
    FORD,
    BMW
}
class Car
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public CarManufacturer Manufacturer { get; set; }
    public string Name { get; set; }
}

class Ford:Car
{
    public Ford()
    {
        Manufacturer = CarManufacturer.FORD;
    }
    public string OnlyFord { get; set; }
}

class BMW :Car
{
    public BMW()
    {
        Manufacturer = CarManufacturer.BMW; ;
    }
    public string OnlyBMW { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

反序列化

Car CurrentCar = new Ford { Name = "Foard Car", OnlyFord = "spacific feature in Ford Cars" };
string json = JsonSerializer.Serialize(CurrentCar, CurrentCar.GetType());
Console.WriteLine(json);
Run Code Online (Sandbox Code Playgroud)

这应该可以解决您的问题,但它有一些缺点

  1. 您将对同一个对象进行两次反序列化!
  2. 向模型添加一些属性以用作类型鉴别器
  3. 如果您的基类是抽象类,则此解决方案将不起作用

为了克服这个问题,你应该编写自定义转换器支持多态反序列化,这会自动将类型鉴别器添加到生成的json中,而不向你的类添加任何值