本文介绍了如何对3种对象类型中的任何一种进行序列化/反序列化,其中一种包含抽象类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过网络发送3个.net对象:

I am sending 3 .net objects over the network:

 - List<int>
 - List<ParentObject>
 - string

这是我进行序列化的方式(所有类型都相同):

This is how I'm serializing (same for all types):

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

        string message = JsonConvert.SerializeObject(listOfParents, JSsettings);
        //listOfParents is  of type List<ParentObject>

ParentObject是一个抽象类,有两个子类.它具有一个属性来获取它代表的子类型.

The ParentObject is an abstract class and has two child classes. It has a property to get which child type it represents.

public enum EntityType {Child1, Child2};

class ParentObject
{
  public EntityType et { get; set; }
  //..other members
}

我想根据接收到的3个对象中的哪一个来调用3个不同的函数.

I want to call 3 different functions based on which of the 3 objects is received.

Object genericObject = JsonConvert.DeserializeObject(message, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto
            });

        if (genericObject is List<int>)
        {
          List<int> myList= (List<int>)genericObject;
          myfunction1(myList);
        }
        if (genericObject is List<ParentObject>)
        {
         //etc..

ParentObject在DeserializeObject()处引起问题,因为它说无法创建类型为ParentObject的实例.类型是接口或抽象类,无法实例化".因此,我想我可能需要在上使用CustomCreationConverter. http://james.newtonking.com/projects/json/help/index.html?topic=html/CustomCreationConverter.htm

The ParentObject is causing problems at DeserializeObject() because it says "Could not create an instance of type ParentObject. Type is an interface or abstract class and cannot be instantiated". So I was thinking I might need to use CustomCreationConverter at http://james.newtonking.com/projects/json/help/index.html?topic=html/CustomCreationConverter.htm

这仍然不能解决我的问题,因为CustomCreationConverter在反序列化期间需要类型,而在反序列化之后需要检查类型.

That still wouldn't solve my problem since the CustomCreationConverter needs the type during deserialization whereas I don't check the type until after deserialization.

有解决问题的建议吗?

推荐答案

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

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.

这篇关于如何对3种对象类型中的任何一种进行序列化/反序列化,其中一种包含抽象类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

阿里云证书,YYDS!

05-22 12:00