Json.net 自定义枚举转换器

4
我目前在我的应用程序中使用Json.net来消费json。 我使用的API为枚举类型发送特定的字符串格式,例如:
对于类型为TemperatureType的枚举,其值为fahrenheit、Celcius
json的值是: {"result":["TemperatureType_fahrenheit","TemperatureType_Celcius"]}
我想使用转换器直接将其管理,以获取IList,但也适用于其他枚举类型。
有人有想法吗?
我尝试使用自定义JsonConverter:
  if (reader.TokenType == JsonToken.String && reader.Value != null)
  {
      string value = reader.Value.ToString();
      var splitValues = value.Split('_');
      if (splitValues.Length == 2)
      {
         var type = Type.GetType(splitValues[0]);
         return Enum.Parse(type, splitValues[1]);
      }
  }

问题出在GetType属性上,因为我没有指定所需类型的参数和命名空间。

  1. 你的JSON似乎无效。开头不应该有{"吗?
  2. 这是如何装饰JSON.NET StringEnumConverter的重复吗?
- dbc
关于装饰,我已经看到了这个线程,但如果可能的话,我不想添加字符串装饰器,以避免开发人员出现错误。 - Tchoupi
1个回答

9
枚举类型是ReadJsonobjectType参数。但是,需要注意以下几点:
  1. 您需要处理可为空的枚举类型。
  2. 您需要处理[Flag]枚举。Json.NET将其写为逗号分隔的值列表。
  3. 您需要处理具有无效值的枚举情况。当StringEnumConverter.AllowIntegerValues == true时,Json.NET将其写为数值,并在其他情况下引发异常。
这是StringEnumConverter的子类,通过调用基类并根据需要添加或删除类型前缀来处理这些情况:
public class TypePrefixEnumConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        bool isNullable = (Nullable.GetUnderlyingType(objectType) != null);
        Type enumType = (Nullable.GetUnderlyingType(objectType) ?? objectType);
        if (!enumType.IsEnum)
            throw new JsonSerializationException(string.Format("type {0} is not a enum type", enumType.FullName));
        var prefix = enumType.Name + "_";

        if (reader.TokenType == JsonToken.Null)
        {
            if (!isNullable)
                throw new JsonSerializationException();
            return null;
        }

        // Strip the prefix from the enum components (if any).
        var token = JToken.Load(reader);
        if (token.Type == JTokenType.String)
        {
            token = (JValue)string.Join(", ", token.ToString().Split(',').Select(s => s.Trim()).Select(s => s.StartsWith(prefix) ? s.Substring(prefix.Length) : s).ToArray());
        }

        using (var subReader = token.CreateReader())
        {
            while (subReader.TokenType == JsonToken.None)
                subReader.Read();
            return base.ReadJson(subReader, objectType, existingValue, serializer); // Use base class to convert
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var array = new JArray();
        using (var tempWriter = array.CreateWriter())
            base.WriteJson(tempWriter, value, serializer);
        var token = array.Single();

        if (token.Type == JTokenType.String && value != null)
        {
            var enumType = value.GetType();
            var prefix = enumType.Name + "_";
            token = (JValue)string.Join(", ", token.ToString().Split(',').Select(s => s.Trim()).Select(s => (!char.IsNumber(s[0]) && s[0] != '-') ? prefix + s : s).ToArray());
        }

        token.WriteTo(writer);
    }
}

然后,你可以在任何可以使用StringEnumConverter的地方使用它,例如:

        var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new TypePrefixEnumConverter() } };
        var json = JsonConvert.SerializeObject(myClass, Formatting.Indented, settings);

太棒了,这正是我在寻找的,现在我更加准确地理解了 JSON 转换器。谢谢! - Tchoupi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接