Created
December 1, 2021 14:52
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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