且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何对3种对象类型中的任何一种进行序列化/反序列化,其中一种包含抽象类?

更新时间:2021-12-23 21:56:37

如果我使用这样定义的对象:

If I use objects defined like this:

public enum EntityType { Child1, Child2 };

abstract class ParentObject
{
    public EntityType et { get; set; }
}

class ChildClass : ParentObject
{
    public int ChildClassProp { get; set; }

    public ChildClass()
    {
        this.et = EntityType.Child1;
    }
}

class ChildClass2 : ParentObject
{
    public int ChildClass2Prop { get; set; }

    public ChildClass2()
    {
        this.et = EntityType.Child2;
    }
}

然后我可以像这样愉快地反序列化派生类(ChildClassChildClass2)到ParentObject:

Then I can happily deserialize derived classes(ChildClass and ChildClass2) to ParentObject like this:

JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects
};

List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });

string message = JsonConvert.SerializeObject(list,
      Newtonsoft.Json.Formatting.Indented, JSsettings);

list = JsonConvert.DeserializeObject<List<ParentObject>>(message, JSsettings);

message的位置如下:

[
  {
    "$type": "ConsoleApplication4.ChildClass, ConsoleApplication4",
    "ChildClassProp": 1,
    "et": 0
  },
  {
    "$type": "ConsoleApplication4.ChildClass2, ConsoleApplication4",
    "ChildClass2Prop": 2,
    "et": 1
  }
]   

此键的关键是使用TypeNameHandling = TypeNameHandling.Auto进行序列化和反序列化.使用TypeNameHandling.Arrays创建一条如下所示的消息:

The key in this one was using TypeNameHandling = TypeNameHandling.Auto for both serialization and deserialization. Using TypeNameHandling.Arrays creates a message that looks like this:

{
  "$type": "System.Collections.Generic.List`1[[ConsoleApplication4.ParentObject, ConsoleApplication4]], mscorlib",
  "$values": [
    {
      "ChildClassProp": 1,
      "et": 0
    },
    {
      "ChildClass2Prop": 2,
      "et": 1
    }
  ]
}

请注意,不包括列表项的类型,仅包括列表的类型,因此会出现错误.

Note that the types of the list items are not included, only the type of the list, hence the error you were getting.

我认为,按照您想要的方式工作的最简单方法是定义一个像这样的简单类,该类充当要序列化的对象的薄包装:

I think the easiest way to get this working the way you want is to define a simple class like this one that acts as a thin wrapper around the object you are serializing:

class ObjectContainer
{
    public object Data { get; set; }
}

然后,代码将如下所示(请注意对TypeNameHandling.Auto的更改):

Then the code would look like this (note the change to TypeNameHandling.Auto):

JsonSerializerSettings JSsettings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto
};

List<ParentObject> list = new List<ParentObject>();
list.Add(new ChildClass() { ChildClassProp = 1 });
list.Add(new ChildClass2() { ChildClass2Prop = 2 });

ObjectContainer container = new ObjectContainer()
{
    Data = list
};

string message = JsonConvert.SerializeObject(container,
      Newtonsoft.Json.Formatting.Indented, JSsettings);

var objectContainer = JsonConvert.DeserializeObject<ObjectContainer>(message, JSsettings);

if (objectContainer.Data is List<int>)
{
    Console.Write("objectContainer.Data is List<int>");
}
else if (objectContainer.Data is List<ParentObject>)
{
    Console.Write("objectContainer.Data is List<ParentObject>");
}
else if (objectContainer.Data is string)
{
    Console.Write("objectContainer.Data is string");
}

我之所以选择这种方法,是因为Json.Net将负责几乎所有工作.只需调用非泛型JsonConvert.DeserializeObject方法就可以了,但是您将需要做其他工作,因为此方法将返回JContainer,而不是object.

The reason I have gone for this approach is that Json.Net will take care of almost all the work. Simply calling the non-generic JsonConvert.DeserializeObject method is fine, but you would then need to do additional work as this method returns a JContainer, not an object.