私はいくつかの継承があります。逆シリアル化のためにカスタムJsonConverter
が必要です。私はここでは、特定のプロパティの存在に基づいてタイプを決定する非常に簡単なアプローチを使用しています。コンバータをDeserializeObjectに渡さずに抽象アイテムのリストを逆シリアル化する方法
重要な注意:私実際コードで、私はDeserializeObject
通話に触れることができない、すなわち、私はそこにカスタム変換器を追加することはできません。私はこれがある程度XY問題であることを知っており、そのような私の答えは、私が望むものは不可能であるかもしれないことを認識しています。限り、これは私の質問はthis questionから少し異なることがわかります。ここで
は、私の状況のREPROです:
abstract class Mammal { }
class Cat : Mammal { public int Lives { get; set; } }
class Dog : Mammal { public bool Drools { get; set; } }
class Person
{
[JsonConverter(typeof(PetConverter))]
public Mammal FavoritePet { get; set; }
[JsonConverter(typeof(PetConverter))]
public List<Mammal> OtherPets { get; set; }
}
そして、これは、カスタムコンバータです:
public class PetConverter : JsonConverter
{
public override bool CanConvert(Type objectType) { return objectType == typeof(Mammal); }
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
JObject jsonObject = JObject.Load(reader);
if (jsonObject["Lives"] != null) return jsonObject.ToObject<Cat>(serializer);
if (jsonObject["Drools"] != null) return jsonObject.ToObject<Dog>(serializer);
return null;
}
}
これはFavoritePet
のため正常に動作しますが、OtherPets
のために多くはない、それはリストだから。
Newtonsoft.Json.JsonReaderException:エラーがJsonReaderからjオブジェクトを読み込むここでNUnitのテストと私の問題を再現する方法です:ので
[TestFixture] class MyTests { [Test] public void CanSerializeAndDeserializeSingleItem() { var person = new Person { FavoritePet = new Cat { Lives = 9 } }; var json = JsonConvert.SerializeObject(person); var actual = JsonConvert.DeserializeObject<Person>(json); Assert.That(actual.FavoritePet, Is.InstanceOf<Cat>()); } [Test] public void CanSerializeAndDeserializeList() { var person = new Person { OtherPets = new List<Mammal> { new Cat { Lives = 9 } } }; var json = JsonConvert.SerializeObject(person); var actual = JsonConvert.DeserializeObject<Person>(json); Assert.That(actual.OtherPets.Single(), Is.InstanceOf<Cat>()); } }
後者の試験は赤です。現在のJsonReaderアイテムはオブジェクトではありません:StartArray。パス「OtherPets」、行1、位置33
私も、その結果OtherPets
のカスタムコンバータ、なしで試してみた:
Newtonsoft.Json.JsonSerializationException:インスタンスを作成できませんでした。タイプJsonConverterLists.Mammalです。型はインタフェースまたは抽象クラスであり、インスタンス化できません。
var actual = JsonConvert.DeserializeObject<Person>(json, new PetConverter());
しかし、繰り返し:パス 'OtherPets [0] .Lives'、行1、位置42
私は何が起こっている理解し、私も、私はでそれを修正することができることを知っています上の注:DeserializeObject
呼び出しを変更することはできません。これは、現在変更できないライブラリ内の関数内にラップされているためです。
アトリビュートベースアプローチで同じことを実行する方法はありますか。各エントリがカスタムコンバータを取るリスト用のビルトインコンバータがありますか?それとも私自身の、別のコンバータをロールバックする必要がありますか?
脚注、再現する方法:
- のVisual Studio 2013 =>新鮮な新しい.NET 4.5。1クラスライブラリ
Install-Package Newtonsoft.Json -Version 7.0.1
Install-Package nunit -Version 2.6.4
あなたは自分の新鮮な名前空間内に上記の3つのコードブロックをドロップ2つ目は失敗見て、NUnitのテストを実行することができます。
あなたのコードは有望そうですが、Stackoverflow例外をスローしています...それはjsonObject.ToObjectはReadJsonを呼び出すようです – Bidou
@Bidou奇妙な、奇妙な。私が覚えている限り、私はこの解決策で*のような*のコードを使用していました。単体テストは正常に動作しました。あなたのレプロも*まったく同じですか、微妙に違いますか?どのバージョンのNewtonSoftを使いましたか? – Jeroen
Mmhmhm私は、 'DefaultContractResolver'から派生した新しいクラスを作成することで動作させることができました。これは、この奇妙な行動を防ぐ... – Bidou