C#でJSON形式の文字列をクラスのインスタンスに変換する際、基底クラスのプロパティに格納される具体的な派生クラスの型をJSONの値に基づいて切り替えたい場合があります。このようなシナリオでは、Newtonsoft.Json
ライブラリを使用してJsonConverter
をカスタマイズする方法があります。この記事では、この実装方法について詳しく解説します。
具体的なユースケース
以下のようなクラス構造を考えます。
public abstract class Animal
{
public string Type { get; set; }
public string Name { get; set; }
}
public class Dog : Animal
{
public string Breed { get; set; }
}
public class Cat : Animal
{
public bool LikesMilk { get; set; }
}
public class Zoo
{
public Animal Animal { get; set; }
}
JSONのデータは以下のような形式を想定します。
{
"Animal": {
"Type": "Dog",
"Name": "Buddy",
"Breed": "Golden Retriever"
}
}
このType
フィールドに基づいて、Animal
プロパティのインスタンスをDog
またはCat
としてデシリアライズしたい場合があります。
JsonConverterのカスタマイズ
まず、基底クラスAnimal
に対応するカスタムJsonConverter
を実装します。
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
[JsonConverter(typeof(AnimalConverter))]
public abstract class Animal { }
public class AnimalConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Animal).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// if (reader.TokenType == JsonToken.Null)
// {
// return null;
// }
JObject jObject = JObject.Load(reader);
string type = jObject["Type"]?.ToString();
Animal animal;
switch (type)
{
case "Dog":
animal = new Dog();
break;
case "Cat":
animal = new Cat();
break;
default:
throw new InvalidOperationException($"Unknown animal type: {type}");
}
serializer.Populate(jObject.CreateReader(), animal);
return animal;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("Serialization is not implemented");
}
}
public class Dog : Animal
{
public string Name { get; set; }
public string Breed { get; set; }
}
public class Cat : Animal
{
public string Name { get; set; }
public bool LikesMilk { get; set; }
}
基底クラスのプロパティにコンバーターを適用
アノテーションを使用することで、Animal
プロパティに対するカスタムコンバーターを簡単に設定できます。
using Newtonsoft.Json;
public class Zoo
{
[JsonConverter(typeof(AnimalConverter))]
public Animal Animal { get; set; }
}
これにより、Zoo
クラスのデシリアライズ時にAnimalConverter
が自動的に適用されます。
使用例
以下は、デシリアライズのコード例です。
using Newtonsoft.Json;
public class Program
{
public static void Main(string[] args)
{
string json = @"{
\"Animal\": {
\"Type\": \"Dog\",
\"Name\": \"Buddy\",
\"Breed\": \"Golden Retriever\"
}
}";
Zoo zoo = JsonConvert.DeserializeObject<Zoo>(json);
Console.WriteLine($"Animal Name: {zoo.Animal.Name}");
if (zoo.Animal is Dog dog)
{
Console.WriteLine($"Breed: {dog.Breed}");
}
}
}
実行結果
上記のコードを実行すると、次のような出力が得られます。
Animal Name: Buddy
Breed: Golden Retriever
まとめ
このように、Newtonsoft.Json
のカスタムJsonConverter
を使用することで、JSONの値に応じて基底クラスのプロパティのインスタンスを動的に切り替えることが可能です。
0 件のコメント:
コメントを投稿