【问题标题】:Can't get enum to convert to json properly using Json.NET无法使用 Json.NET 将枚举正确转换为 json
【发布时间】:2013-11-04 12:37:13
【问题描述】:

我有一个枚举:

public enum Animal 
{ 
    Dog, 
    Cat, 
    BlackBear 
}

我需要将其发送到第三方 API。这个 API 要求我发送的枚举值是小写的,并且偶尔需要下划线。一般来说,他们需要的名称与我使用的枚举命名约定不匹配。

使用https://gooddevbaddev.wordpress.com/2013/08/26/deserializing-c-enums-using-json-net/ 提供的示例,我尝试使用自定义 JsonConverter:

public class AnimalConverter : JsonConverter {
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        var animal = (Animal)value;
        switch (animal)
        {
            case Animal.Dog:
            {
                writer.WriteValue("dog");
                break;
            }
            case Animal.Cat:
            {
                writer.WriteValue("cat");
                break;
            }
            case Animal.BlackBear:
            {
                writer.WriteValue("black_bear");
                break;
            }
        }
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        var enumString = (string)reader.Value;
        Animal? animal = null;
        switch (enumString)
        {
            case "cat":
            {
                animal = Animal.Cat;
                break;
            }
            case "dog":
            {
                animal = Animal.Dog;
                break;
            }
            case "black_bear":
            {
                animal = Animal.BlackBear;
                break;
            }
        }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }
}

回到类的属性,我把属性放在 Animal 上:

[JsonProperty("animal")]
[JsonConverter(typeof(AnimalConverter))]
public Animal ZooAnimals { get; set; }

当我运行程序时,它似乎完全忽略了 JsonConverter,而不是看到“black_bear”或“dog”等预期值,而是看到“BlackBear”和“Dog”。如何让 JsonConverter 实际执行从枚举值的名称到我指定替换该值的字符串的转换?

谢谢!

【问题讨论】:

  • 你能否制作一个简短但完整的程序,例如 LINQPad 来演示问题?我写了一个小的 LINQPad 程序来测试,它在这里使用了转换器。
  • 您在代码示例中引用了AnimalAnimals;你能澄清这两个都指你的枚举吗?对于它的价值,我设法使用以下 sn-p 使您的代码正常工作:Zoo zoo = new Zoo { ZooAnimals = Animal.Cat }; string json = JsonConvert.SerializeObject(zoo);

标签: c# json.net


【解决方案1】:

您无需编写自己的转换器。 Json.NET 的StringEnumConverter 将读取EnumMember 属性。如果您将 enum 更改为此,它将从您想要的值开始序列化。

[JsonConverter(typeof(StringEnumConverter))]
public enum Animals 
{
    [EnumMember(Value = "dog")]
    Dog, 
    [EnumMember(Value = "cat")]
    Cat, 
    [EnumMember(Value = "black_bear")]
    BlackBear 
}

(作为一个小提示,由于Animals 不是标志枚举,它是should be singularAnimal。您应该考虑将其更改为这个。)

【讨论】:

  • 嗨蒂姆,我如何在 .Net 2.0 中使用 EnumMember?
  • @RickyJiao 我想我会创建自己的转换器,基于StringEnumConverter (see source),并使其与我自己的EnumMemberAttribute 类一起工作,基于EnumMemberAttribute(只是需要一个属性和构造函数)。
  • 你知道为什么 StringEnumConverter 使用 EnumMember 而不是 Json.NET JsonProperty 吗?因为我在其他任何地方都使用JsonProperty,但显然不适用于枚举..
  • @Kapé 我不能说我真的这样做;使用内置类型而不是自定义类型似乎很奇怪,就像在其他地方通常所做的那样。这是我的猜测:枚举成员不代表属性(即键/值对中的键),而是值,因此使用JsonProperty 来描述它是没有意义的。
  • 似乎您需要为枚举提供 DataContract 属性才能使 EnumMember 工作,因为上面的内容对我不起作用。像这样[DataContract] public enum Animals....
【解决方案2】:
// Might return null, better to use try catch
public static Animals GetEnum(string val)
{
    return (Animals)Enum.Parse(typeof(Animals), val, true);
}

public static string GetName(Animals an)
{
    return Enum.GetName(typeof(Animals), an);
}

public static string GetReplace(Animals an)
{
    var get = GetName(an);
    var tempstr = "";
    int getch = 0;
    foreach (var chr in get.ToCharArray())
    {
        if (chr == chr.ToUpper())
        {
            getch++;
            // Second up value char
            if (getch == 2)
            {
                tempstr += "_" + chr;
            }
            else
            {
                tempstr += chr;
            }
        }
        else
        {
             tempstr += chr;
        }
    }
    return tempstr;
}

【讨论】:

  • 不能使用它,因为枚举值的名称必须偶尔更改。例如,给定枚举值“BlackBear”,它必须转换为显示值“black_bear”。
  • @Xaniff GetEnum(val.Replace("_", "").Replace(" ", "")); 并看到编辑,使用这个函数:GetReplace(animal);
  • @Xaniff 如果不能使用上限值,请制作最终字符串 `GetReplace(animal).ToLower()'
  • 我想我真的在寻找一个更通用的解决方案,所以我可以通过一个属性指定我想为枚举返回什么值,而不是每次都写一个这样的转换(尤其是看到第三方 API 的命名规则相当不一致)。不过谢谢!
【解决方案3】:

我认为您的ConConvert() 实现不正确。 应该是:

public override bool CanConvert(Type objectType)
{
    return objectType == typeof(Animals);
}

【讨论】:

  • 尝试将其从字符串翻转到 Animals,它仍然返回“BlackBear”而不是“black_bear”。不过谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 2013-06-26
  • 2023-04-11
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多