簡體   English   中英

如何對3種對象類型中的任何一種進行序列化/反序列化,其中一種包含抽象類?

[英]How to serialize-deserialize any of 3 object types, one of which contains an abstract class?

我正在通過網絡發送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 反序列化期間需要類型反序列化之后才檢查類型。

有解決問題的建議嗎?

如果我使用這樣定義的對象:

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方法就可以了,但是您需要做一些額外的工作,因為此方法返回的是JContainer ,而不是object

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM