StringEnumConverter
Converts an Enum to and from its name string value.
using Newtonsoft.Json.Utilities;
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
namespace Newtonsoft.Json.Converters
{
public class StringEnumConverter : JsonConverter
{
private static readonly ThreadSafeStore<Type, BidirectionalDictionary<string, string>> EnumMemberNamesPerType = new ThreadSafeStore<Type, BidirectionalDictionary<string, string>>(InitializeEnumType);
public bool CamelCaseText { get; set; }
public bool AllowIntegerValues { get; set; }
public StringEnumConverter()
{
AllowIntegerValues = true;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
writer.WriteNull();
else {
Enum enum = (Enum)value;
string text = enum.ToString("G");
if (char.IsNumber(text[0]) || text[0] == '-')
writer.WriteValue(value);
else {
BidirectionalDictionary<string, string> bidirectionalDictionary = EnumMemberNamesPerType.Get(enum.GetType());
string[] array = text.Split(new char[1] {
','
});
for (int i = 0; i < array.Length; i++) {
string text2 = array[i].Trim();
bidirectionalDictionary.TryGetByFirst(text2, out string second);
second = (second ?? text2);
if (CamelCaseText)
second = StringUtils.ToCamelCase(second);
array[i] = second;
}
string value2 = string.Join(", ", array);
writer.WriteValue(value2);
}
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
bool flag = ReflectionUtils.IsNullableType(objectType);
Type type = flag ? Nullable.GetUnderlyingType(objectType) : objectType;
if (reader.TokenType == JsonToken.Null) {
if (!ReflectionUtils.IsNullableType(objectType))
throw JsonSerializationException.Create(reader, "Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
return null;
}
try {
if (reader.TokenType == JsonToken.String) {
string text = reader.Value.ToString();
if (text == string.Empty && flag)
return null;
BidirectionalDictionary<string, string> map = EnumMemberNamesPerType.Get(type);
string value;
if (text.IndexOf(',') != -1) {
string[] array = text.Split(new char[1] {
','
});
for (int i = 0; i < array.Length; i++) {
string enumText = array[i].Trim();
array[i] = ResolvedEnumName(map, enumText);
}
value = string.Join(", ", array);
} else
value = ResolvedEnumName(map, text);
return Enum.Parse(type, value, true);
}
if (reader.TokenType == JsonToken.Integer) {
if (!AllowIntegerValues)
throw JsonSerializationException.Create(reader, "Integer value {0} is not allowed.".FormatWith(CultureInfo.InvariantCulture, reader.Value));
return ConvertUtils.ConvertOrCast(reader.Value, CultureInfo.InvariantCulture, type);
}
} catch (Exception ex) {
throw JsonSerializationException.Create(reader, "Error converting value {0} to type '{1}'.".FormatWith(CultureInfo.InvariantCulture, MiscellaneousUtils.FormatValueForPrint(reader.Value), objectType), ex);
}
throw JsonSerializationException.Create(reader, "Unexpected token {0} when parsing enum.".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
}
private static string ResolvedEnumName(BidirectionalDictionary<string, string> map, string enumText)
{
map.TryGetBySecond(enumText, out string first);
first = (first ?? enumText);
return first;
}
public override bool CanConvert(Type objectType)
{
Type type = ReflectionUtils.IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) : objectType;
return type.IsEnum();
}
private static BidirectionalDictionary<string, string> InitializeEnumType(Type type)
{
BidirectionalDictionary<string, string> bidirectionalDictionary = new BidirectionalDictionary<string, string>(StringComparer.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase);
foreach (FieldInfo field in TypeExtensions.GetFields(type)) {
string name = field.Name;
string text = (from EnumMemberAttribute a in CustomAttributeExtensions.GetCustomAttributes(field, typeof(EnumMemberAttribute), true)
select a.Value).SingleOrDefault() ?? field.Name;
if (bidirectionalDictionary.TryGetBySecond(text, out string _))
throw new InvalidOperationException("Enum name '{0}' already exists on enum '{1}'.".FormatWith(CultureInfo.InvariantCulture, text, type.get_Name()));
bidirectionalDictionary.Set(name, text);
}
return bidirectionalDictionary;
}
}
}