0

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

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

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

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

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

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

public enum EntityType {Child1, Child2};

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

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

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 类型的实例。类型是接口或抽象类,无法实例化”。所以我想我可能需要在http://james.newtonking.com/projects/json/help/index.html?topic=html/CustomCreationConverter.htm使用 CustomCreationConverter

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

有什么解决问题的建议吗?

4

1 回答 1

1

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

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

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会创建如下所示的消息:

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

请注意,不包括列表项的类型,仅包括列表的类型,因此您得到的错误。

编辑:

我认为让这个工作以你想要的方式工作的最简单方法是定义一个像这样的简单类,它充当你正在序列化的对象的薄包装器:

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

然后代码将如下所示(注意对 的更改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方法就可以了,但是你需要做额外的工作,因为这个方法返回的是 a JContainer,而不是 a object

于 2013-03-19T06:43:56.270 回答