Skip to content

Instantly share code, notes, and snippets.

@souzagustavo
Created December 1, 2021 14:52
Show Gist options
  • Save souzagustavo/fec600d932c23b6302fca6531b44e93f to your computer and use it in GitHub Desktop.
Save souzagustavo/fec600d932c23b6302fca6531b44e93f to your computer and use it in GitHub Desktop.
Used for custom serialization and deserialization of enum type fields, tolerating parse errors
public class TolerantStringEnumConverter<TEnum> : JsonConverter<TEnum>
{
const string DefaultIndex = "0";
const string DefaultEnumNone = "None";
public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
bool isNullable = IsNullableType(typeToConvert);
Type enumType = GetEnumType(typeToConvert);
if (enumType.BaseType != typeof(Enum))
throw new InvalidCastException("TEnum is not an enumeration type");
string[] names = Enum.GetNames(enumType);
if (reader.TokenType == JsonTokenType.String)
{
string enumText = reader.GetString();
if (!string.IsNullOrWhiteSpace(enumText))
{
string match = names
.FirstOrDefault(n => string.Equals(n, enumText, StringComparison.OrdinalIgnoreCase));
if (match != null)
return (TEnum)Enum.Parse(enumType, match);
}
}
else if (TryGetAsIntValue(reader, out int enumVal))
{
int[] values = (int[])Enum.GetValues(enumType);
if (values.Contains(enumVal))
return (TEnum)Enum.Parse(enumType, enumVal.ToString());
}
if (!isNullable)
{
string defaultName = names
.FirstOrDefault(n => string.Equals(n, DefaultEnumNone, StringComparison.OrdinalIgnoreCase));
if (defaultName != null)
return (TEnum)Enum.Parse(enumType, defaultName);
}
return (TEnum)Enum.Parse(enumType, DefaultIndex);
}
public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString());
private bool IsNullableType(Type type)
=> (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>));
private Type GetEnumType(Type type)
=> IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type;
private bool TryGetAsIntValue(Utf8JsonReader reader, out int value)
{
value = 0;
if (reader.TokenType != JsonTokenType.Number)
return false;
return (reader.TryGetInt32(out value));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment