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 は抽象クラスで、2 つの子クラスがあります。それが表す子の型を取得するプロパティがあります。

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;
    }
}

ChildClass次に、派生クラス (およびChildClass2) を喜んでデシリアライズして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返すため、追加の作業が必要になります。JContainerobject

于 2013-03-19T06:43:56.270 に答える