Json.net自定义枚举转换器 [英] Json.net Custom enum converter

查看:197
本文介绍了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属性,因为我没有获取参数,指示所需的类型,没有命名空间

解决方案

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


  1. 您需要处理可空的枚举类型。

  2. 您需要处理 [Flag] 枚举。 Json.NET将这些值作为逗号分隔的值列表。

  3. 您需要处理具有无效值的枚举的情况。 Json.NET在 StringEnumConverter.AllowIntegerValues == true 时将数据写入数值,否则会引发异常。

这里是 StringEnumConverter ,通过调用基类来处理这些情况,然后在适当的时候添加或删除类型前缀:



pre $ public class TypePrefixEnumConverter:StringEnumConverter
{
public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
{
bool isNullable =(Nullable.GetUnderlyingType(objectType)!= null);
类型enumType =(Nullable.GetUnderlyingType(objectType)?objectType);
if(!enumType.IsEnum)
throw new JsonSerializationException(string.Format(type {0}不是枚举类型,enumType.FullName));
var prefix = enumType.Name +_;

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

//从枚举组件中剥离前缀(如果有)。
var token = JToken.Load(reader);
if(token.Type == JTokenType.String)
{
token =(JValue)string.Join(,,token.ToString()Split(',')。选择(s => s.Trim())。选择(s => s.StartsWith(prefix)?s.Substring(prefix.Length):s).ToArray());
}

使用(var subReader = token.CreateReader())
{
while(subReader.TokenType == JsonToken.None)
subReader。读();
return base.ReadJson(subReader,objectType,existingValue,serializer); //使用基类转换
}
}

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(',')选择(s => s.Trim())Select(s => !char.IsNumber(s [0])&& s [0]!=' - ')?prefix + s:s).ToArray());
}

token.WriteTo(writer);
}
}

然后,您可以使用它,无论何处可以使用< a href =http://www.newtonsoft.com/json/help/html/SerializeWithJsonConverters.htm =noreferrer> StringEnumConverter ,for实例:

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


I'm currently using Json.net to consume json in my app. The API I use send me a specific string format for enum for example:

For an enum of type TemperatureType with values fahrenheit, Celcius

The json value is: {"result":["TemperatureType_fahrenheit","TemperatureType_Celcius"]}

I would like to use a converter to directly manage it to get an IList<TemperatureType> but also working for other enum types.

Does anybody have an idea ?

I've try to use a custom 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]);
      }
  }

The problem is the GetType Property because I haven't got parameters indicating the desired type and no namespace

解决方案

The enum type is the objectType argument to ReadJson. However, a few points:

  1. You need to handle nullable enum types.
  2. You need to handle [Flag] enumerations. Json.NET writes these as comma-separated lists of values.
  3. You need to handle the case of an enum with an invalid value. Json.NET writes these as numeric values when StringEnumConverter.AllowIntegerValues == true and throws an exception otherwise.

Here is a subclass of StringEnumConverter that handles these cases by calling the base class then adding or removing the type prefix when appropriate:

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

Then, you can use it wherever you could use StringEnumConverter, for instance:

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

这篇关于Json.net自定义枚举转换器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆