简体   繁体   English

使用Json.Net进行C#枚举反序列化:将值转换为类型时出错

[英]C# Enum deserialization with Json.Net: Error converting value to type

I'm using Json.NET to serialize/deserialize some JSON APIs. 我正在使用Json.NET来序列化/反序列化一些JSON API。

The API response have some integer values that map to an Enum defined in the application. API响应具有一些整数值,这些值映射到应用程序中定义的枚举。

The enum is like this: 枚举是这样的:

public enum MyEnum
    {
        Type1,
        Type2,
        Type3
}

and the json API response has the following: 并且json API响应具有以下内容:

{
        "Name": "abc",
        "MyEnumValue":"Type1"
}

sometimes the API returns a value for the MyEnumValue field that's not defined in my enum, like this: 有时,API会返回MyEnumValue字段的值,该字段未在我的枚举中定义,如下所示:

{
            "Name": "abc",
            "MyEnumValue":"Type4"
    }

That throws an exception: 这引发了一个例外:

Error converting value "Type4" to type 'MyEnum' 将值“Type4”转换为“MyEnum”类型时出错

Is there a way to handle this error by assigning a default value or something to avoid the application crash? 有没有办法通过分配默认值或什么来避免应用程序崩溃来处理此错误?

Let's say we have the following json string: 假设我们有以下json字符串:

[
    {
        "Name": "abc",
        "MyEnumValue": "Type1"
    },
    {
        "Name": "abcd",
        "MyEnumValue": "Type2"
    },
    {
        "Name": "abcde",
        "MyEnumValue": "Type3"
    }    ,
    {
        "Name": "abcdef",
        "MyEnumValue": "Type4"
    }
]

and the following class and enum: 和以下类和枚举:

public class MyClass
{
    public string Name { get; set; }

    public MyEnum MyEnumValue { get; set; }
}

public enum MyEnum
{
    Type1,
    Type2,
    Type3
}

As it can be noticed, the json string array contains item (the last one), that cannot be correctly mapped to the MyEnum . 可以注意到,json字符串数组包含无法正确映射到MyEnum项(最后一项)。 To avoid deserialization errors you can use the following code snippet: 为避免反序列化错误,您可以使用以下代码段:

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

where the jsonStr variable is the posted json string above. 其中jsonStr变量是上面发布的json字符串。 In the above code sample, if MyEnumValue cannot be correctly interpreted, it is set to a default value of Type2 . 在上面的代码示例中,如果无法正确解释MyEnumValue ,则将其设置为Type2的默认值。

Example: https://dotnetfiddle.net/WKd2Lt 示例: https//dotnetfiddle.net/WKd2Lt

The only way I see it, you should write your own converter. 我看到它的唯一方法,你应该编写自己的转换器。 But half of work is already done in class StringEnumConverter . 但是一半的工作已经在StringEnumConverter类中StringEnumConverter We can override only ReadJson method 我们只能覆盖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;
        }
    }
}

An alternative, if you don't want to create a custom converter, is to map it to a private string field in your DTO and then use Enum.TryParse in that field's property getter: 如果您不想创建自定义转换器,另一种方法是将其映射到DTO中的私有字符串字段,然后在该字段的属性getter中使用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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM