web-dev-qa-db-ja.com

Json.netは派生型をシリアライズ/デシリアライズしますか?

json.net(newtonsoft)
ドキュメントを調べていますが、これまたはそれを行うための最良の方法については何も見つかりません。

public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

これで、シリアル化されたリストにDerivedオブジェクトができました。リストを逆シリアル化し、派生型を取得するにはどうすればよいですか?

83
Will

タイプをtextに保存している場合(このシナリオのように)、JsonSerializerSettingsを使用できます。

参照: Newtonsoft JSON.NETでJSONをIEnumerable <BaseType>にデシリアライズする方法

しかし、注意してください。TypeNameHandling = TypeNameHandling.None以外のものを使用すると、 セキュリティの脆弱性 に達する可能性があります。

36
kamranicus

タイプ名処理を有効にし、それを設定パラメーターとして(デ)シリアライザーに渡す必要があります。

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

これにより、派生クラスが正しくデシリアライズされます。欠点は、使用しているすべてのオブジェクトに名前を付けることです。そのため、オブジェクトを入れるリストに名前を付けます。

88
Madmenyo

質問はとても人気があるので、型プロパティ名とその値を制御したい場合に何をするかを追加すると便利かもしれません。

長い道のりは、typeプロパティを手動でチェックして設定することにより、(_)シリアル化を処理するカスタムJsonConvertersを記述することです。

より簡単な方法は、 JsonSubTypes を使用することです。これは、属性を介してすべての定型文を処理します。

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}
12
rzippo