Json.net Custom enum converter

前端 未结 1 496
长发绾君心
长发绾君心 2020-12-06 08:31

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 Tempe

相关标签:
1条回答
  • 2020-12-06 09:13

    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);
    
    0 讨论(0)
提交回复
热议问题