Json.NETを使用していくつかのJSONAPIをシリアル化/逆シリアル化します。
API応答には、アプリケーションで定義された列挙型にマップされるいくつかの整数値があります。
列挙型は次のようになります。
public enum MyEnum
{
Type1,
Type2,
Type3
}
jsonAPI応答には次のものがあります。
{
"Name": "abc",
"MyEnumValue":"Type1"
}
次のように、APIが列挙型で定義されていないMyEnumValueフィールドの値を返すことがあります。
{
"Name": "abc",
"MyEnumValue":"Type4"
}
それは例外をスローします:
値 "Type4"をタイプ 'MyEnum'に変換中にエラーが発生しました
アプリケーションのクラッシュを回避するためにデフォルト値などを割り当てることで、このエラーを処理する方法はありますか?
次のjson文字列があるとします。
[
{
"Name": "abc",
"MyEnumValue": "Type1"
},
{
"Name": "abcd",
"MyEnumValue": "Type2"
},
{
"Name": "abcde",
"MyEnumValue": "Type3"
} ,
{
"Name": "abcdef",
"MyEnumValue": "Type4"
}
]
および次のクラスと列挙型:
public class MyClass
{
public string Name { get; set; }
public MyEnum MyEnumValue { get; set; }
}
public enum MyEnum
{
Type1,
Type2,
Type3
}
お気づきのとおり、json文字列配列にはアイテム(最後のアイテム)が含まれていますが、これはMyEnum
に正しくマップできません。デシリアライズエラーを回避するには、次のコードスニペットを使用できます。
static void Main(string[] args)
{
var serializationSettings = new JsonSerializerSettings
{
Error = HandleDeserializationError
};
var lst = JsonConvert.DeserializeObject<List<MyClass>>(jsonStr, serializationSettings);
}
public static void HandleDeserializationError(object sender, ErrorEventArgs errorArgs)
{
errorArgs.ErrorContext.Handled = true;
var currentObj = errorArgs.CurrentObject as MyClass;
if (currentObj == null) return;
currentObj.MyEnumValue = MyEnum.Type2;
}
ここで、jsonStr
変数は、上記の投稿されたjson文字列です。上記のコードサンプルでは、MyEnumValue
を正しく解釈できない場合、デフォルト値のType2
に設定されています。
私がそれを見る唯一の方法は、あなた自身のコンバーターを書くべきです。しかし、作業の半分はすでにクラスStringEnumConverter
で行われています。オーバーライドできるのはReadJson
メソッドのみです
class Program
{
static void Main(string[] args)
{
const string json = @"{
'Name': 'abc',
'Type':'Type4'
}";
// uncomment this if you want to use default value other then default enum first value
//var settings = new JsonSerializerSettings();
//settings.Converters.Add(new FooTypeEnumConverter { DefaultValue = FooType.Type3 });
//var x = JsonConvert.DeserializeObject<Foo>(json, settings);
var x = JsonConvert.DeserializeObject<Foo>(json);
}
}
public class Foo
{
public string Name { get; set; }
public FooType Type { get; set; }
}
public enum FooType
{
Type1,
Type2,
Type3
}
public class FooTypeEnumConverter : StringEnumConverter
{
public FooType DefaultValue { get; set; }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
{
return base.ReadJson(reader, objectType, existingValue, serializer);
}
catch (JsonSerializationException)
{
return DefaultValue;
}
}
}
カスタムコンバーターを作成したくない場合は、それをDTOのプライベート文字列フィールドにマップしてから、そのフィールドのプロパティゲッターでEnum.TryParseを使用することもできます。
public class MyClass
{
[JsonProperty("MyEnumValue")]
private string myEnumValue;
public string Name { get; set; }
[JsonIgnore]
public MyEnum MyEnumValue
{
get
{
MyEnum outputValue = MyEnum.Default;
Enum.TryParse(myEnumValue, out outputValue);
return outputValue;
}
}
}