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

Posted

技术标签:

【中文标题】使用 Json.Net 进行 C# 枚举反序列化:将值转换为类型时出错【英文标题】:C# Enum deserialization with Json.Net: Error converting value to type 【发布时间】:2015-10-17 13:06:15 【问题描述】:

我正在使用 Json.NET 序列化/反序列化一些 JSON API。

API 响应有一些整数值映射到应用程序中定义的枚举。

枚举是这样的:

public enum MyEnum
    
        Type1,
        Type2,
        Type3

json API 响应如下:


        "Name": "abc",
        "MyEnumValue":"Type1"

有时 API 返回一个未在我的枚举中定义的 MyEnumValue 字段的值,如下所示:


            "Name": "abc",
            "MyEnumValue":"Type4"
    

这会引发异常:

将值“Type4”转换为类型“MyEnum”时出错

有没有办法通过分配默认值或其他方式来处理此错误以避免应用程序崩溃?

【问题讨论】:

您是否尝试为属性newtonsoft.com/json/help/html/… 指定DefaultValue 谢谢,我试过了还是抛出异常 【参考方案1】:

假设我们有以下 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。为避免反序列化错误可以使用以下代码sn-p:

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

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

【讨论】:

谢谢,这是一个不错的解决方案 Yikes,如何分配默认值作为解决方案?也许Type5或Type6或TypeX不能等同于Type2?关键是客户端无法预测服务器将来可能返回什么,因此假设您可以分配默认值是危险的。【参考方案2】:

我看到的唯一方法是,您应该编写自己的转换器。但是在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;
        
    

【讨论】:

谢谢,这可以是另一种替代解决方案【参考方案3】:

如果您不想创建自定义转换器,另一种方法是将其映射到 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;
        
    

【讨论】:

你也可以看看这个问题,json with Enum DisplayName or EnumMember Value

以上是关于使用 Json.Net 进行 C# 枚举反序列化:将值转换为类型时出错的主要内容,如果未能解决你的问题,请参考以下文章

使属性反序列化但不使用 json.net 序列化

C# 使用Json.NET对数据进行序列化和反序列化 | c# json serialize and deserialize using json.net JsonConvert

c# 通过json.net中的JsonConverter进行自定义序列化与反序列化

.NET(C#)通过JSON.NET反序列化Elasticsearch返回响应的结果

使用字符串、int 数组反序列化 json - .net core C#

C#对 Json的序列化和反序列化时出现“k_BackingField”