Json.net自定义枚举转换器

时间:2015-08-17 09:26:29

标签: c# json enums json.net

我目前正在使用Json.net在我的应用中使用json。 我使用的API为枚举发送了一个特定的字符串格式,例如:

对于 TemperatureType 类型的枚举,其值为 fahrenheit, Celcius

json值是: {"result":["TemperatureType_fahrenheit","TemperatureType_Celcius"]}

我想使用转换器来直接管理它 IList<TemperatureType>,但也适用于其他枚举类型。

有人有想法吗?

我尝试使用自定义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 个答案:

答案 0 :(得分:7)

枚举类型是ReadJsonobjectType参数。但是,有几点:

  1. 您需要处理可以为空的枚举类型。
  2. 您需要处理[Flag]枚举。 Json.NET将这些写为以逗号分隔的值列表。
  3. 您需要处理枚举值无效的情况。 Json.NET在StringEnumConverter.AllowIntegerValues == true时将这些值写为数值,否则抛出异常。
  4. 这是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);