<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />

EnumUtils

static class EnumUtils
using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; namespace Newtonsoft.Json.Utilities { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] internal static class EnumUtils { private const char EnumSeparatorChar = ','; private const string EnumSeparatorString = ", "; [System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0, 1, 2, 1 })] private static readonly ThreadSafeStore<StructMultiKey<Type, NamingStrategy>, EnumInfo> ValuesAndNamesPerEnum = new ThreadSafeStore<StructMultiKey<Type, NamingStrategy>, EnumInfo>(InitializeValuesAndNames); private static CamelCaseNamingStrategy _camelCaseNamingStrategy = new CamelCaseNamingStrategy(); private static EnumInfo InitializeValuesAndNames([System.Runtime.CompilerServices.Nullable(new byte[] { 0, 1, 2 })] StructMultiKey<Type, NamingStrategy> key) { Type value = key.Value1; string[] names = Enum.GetNames(value); string[] array = new string[names.Length]; ulong[] array2 = new ulong[names.Length]; for (int i = 0; i < names.Length; i++) { string text = names[i]; FieldInfo field = value.GetField(text, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); array2[i] = ToUInt64(field.GetValue(null)); object text2 = (from EnumMemberAttribute a in field.GetCustomAttributes(typeof(EnumMemberAttribute), true) select a.Value).SingleOrDefault(); bool hasSpecifiedName = text2 != null; if (text2 == null) text2 = text; string text3 = (string)text2; if (Array.IndexOf(array, text3, 0, i) != -1) throw new InvalidOperationException("Enum name '{0}' already exists on enum '{1}'.".FormatWith(CultureInfo.InvariantCulture, text3, value.Name)); array[i] = ((key.Value2 != null) ? key.Value2.GetPropertyName(text3, hasSpecifiedName) : text3); } return new EnumInfo(value.IsDefined(typeof(FlagsAttribute), false), array2, names, array); } [System.Runtime.CompilerServices.NullableContext(0)] [return: System.Runtime.CompilerServices.Nullable(new byte[] { 1, 0 })] public static IList<T> GetFlagsValues<T>(T value) where T : struct { Type typeFromHandle = typeof(T); if (!typeFromHandle.IsDefined(typeof(FlagsAttribute), false)) throw new ArgumentException("Enum type {0} is not a set of flags.".FormatWith(CultureInfo.InvariantCulture, typeFromHandle)); Type underlyingType = Enum.GetUnderlyingType(value.GetType()); ulong num = ToUInt64(value); EnumInfo enumValuesAndNames = GetEnumValuesAndNames(typeFromHandle); IList<T> list = new List<T>(); for (int i = 0; i < enumValuesAndNames.Values.Length; i++) { ulong num2 = enumValuesAndNames.Values[i]; if ((num & num2) == num2 && num2 != 0) ((ICollection<T>)list).Add((T)Convert.ChangeType(num2, underlyingType, CultureInfo.CurrentCulture)); } if (((ICollection<T>)list).Count == 0 && enumValuesAndNames.Values.Any((ulong v) => v == 0)) ((ICollection<T>)list).Add(default(T)); return list; } public static bool TryToString(Type enumType, object value, bool camelCase, [System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string name) { return TryToString(enumType, value, camelCase ? _camelCaseNamingStrategy : null, out name); } public static bool TryToString(Type enumType, object value, [System.Runtime.CompilerServices.Nullable(2)] NamingStrategy namingStrategy, [System.Runtime.CompilerServices.Nullable(2)] [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out string name) { EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey<Type, NamingStrategy>(enumType, namingStrategy)); ulong num = ToUInt64(value); if (!enumInfo.IsFlags) { int num2 = Array.BinarySearch(enumInfo.Values, num); if (num2 >= 0) { name = enumInfo.ResolvedNames[num2]; return true; } name = null; return false; } name = InternalFlagsFormat(enumInfo, num); return name != null; } [return: System.Runtime.CompilerServices.Nullable(2)] private static string InternalFlagsFormat(EnumInfo entry, ulong result) { string[] resolvedNames = entry.ResolvedNames; ulong[] values = entry.Values; int num = values.Length - 1; StringBuilder stringBuilder = new StringBuilder(); bool flag = true; ulong num2 = result; while (num >= 0 && (num != 0 || values[num] != 0)) { if ((result & values[num]) == values[num]) { result -= values[num]; if (!flag) stringBuilder.Insert(0, ", "); string value = resolvedNames[num]; stringBuilder.Insert(0, value); flag = false; } num--; } if (result == 0) { if (num2 != 0) return stringBuilder.ToString(); if (values.Length != 0 && values[0] == 0) return resolvedNames[0]; return null; } return null; } public static EnumInfo GetEnumValuesAndNames(Type enumType) { return ValuesAndNamesPerEnum.Get(new StructMultiKey<Type, NamingStrategy>(enumType, null)); } private static ulong ToUInt64(object value) { bool isEnum; switch (ConvertUtils.GetTypeCode(value.GetType(), out isEnum)) { case PrimitiveTypeCode.SByte: return (ulong)(sbyte)value; case PrimitiveTypeCode.Byte: return (byte)value; case PrimitiveTypeCode.Boolean: return Convert.ToByte((bool)value); case PrimitiveTypeCode.Int16: return (ulong)(short)value; case PrimitiveTypeCode.UInt16: return (ushort)value; case PrimitiveTypeCode.Char: return (char)value; case PrimitiveTypeCode.UInt32: return (uint)value; case PrimitiveTypeCode.Int32: return (ulong)(int)value; case PrimitiveTypeCode.UInt64: return (ulong)value; case PrimitiveTypeCode.Int64: return (ulong)(long)value; default: throw new InvalidOperationException("Unknown enum type."); } } public static object ParseEnum(Type enumType, [System.Runtime.CompilerServices.Nullable(2)] NamingStrategy namingStrategy, string value, bool disallowNumber) { ValidationUtils.ArgumentNotNull(enumType, "enumType"); ValidationUtils.ArgumentNotNull(value, "value"); if (!enumType.IsEnum()) throw new ArgumentException("Type provided must be an Enum.", "enumType"); EnumInfo enumInfo = ValuesAndNamesPerEnum.Get(new StructMultiKey<Type, NamingStrategy>(enumType, namingStrategy)); string[] names = enumInfo.Names; string[] resolvedNames = enumInfo.ResolvedNames; ulong[] values = enumInfo.Values; int? nullable = FindIndexByName(resolvedNames, value, 0, value.Length, StringComparison.Ordinal); if (nullable.HasValue) return Enum.ToObject(enumType, values[nullable.Value]); int num = -1; for (int i = 0; i < value.Length; i++) { if (!char.IsWhiteSpace(value[i])) { num = i; break; } } if (num == -1) throw new ArgumentException("Must specify valid information for parsing in the string."); char c = value[num]; if (char.IsDigit(c) || c == '-' || c == '+') { Type underlyingType = Enum.GetUnderlyingType(enumType); value = value.Trim(); object obj = null; try { obj = Convert.ChangeType(value, underlyingType, CultureInfo.InvariantCulture); } catch (FormatException) { } if (obj != null) { if (disallowNumber) throw new FormatException("Integer string '{0}' is not allowed.".FormatWith(CultureInfo.InvariantCulture, value)); return Enum.ToObject(enumType, obj); } } ulong num2 = 0; int num3; for (int j = num; j <= value.Length; j = num3 + 1) { num3 = value.IndexOf(',', j); if (num3 == -1) num3 = value.Length; int num4 = num3; for (; j < num3 && char.IsWhiteSpace(value[j]); j++) { } while (num4 > j && char.IsWhiteSpace(value[num4 - 1])) { num4--; } int valueSubstringLength = num4 - j; nullable = MatchName(value, names, resolvedNames, j, valueSubstringLength, StringComparison.Ordinal); if (!nullable.HasValue) nullable = MatchName(value, names, resolvedNames, j, valueSubstringLength, StringComparison.OrdinalIgnoreCase); if (!nullable.HasValue) { nullable = FindIndexByName(resolvedNames, value, 0, value.Length, StringComparison.OrdinalIgnoreCase); if (nullable.HasValue) return Enum.ToObject(enumType, values[nullable.Value]); throw new ArgumentException("Requested value '{0}' was not found.".FormatWith(CultureInfo.InvariantCulture, value)); } num2 |= values[nullable.Value]; } return Enum.ToObject(enumType, num2); } private static int? MatchName(string value, string[] enumNames, string[] resolvedNames, int valueIndex, int valueSubstringLength, StringComparison comparison) { int? result = FindIndexByName(resolvedNames, value, valueIndex, valueSubstringLength, comparison); if (!result.HasValue) result = FindIndexByName(enumNames, value, valueIndex, valueSubstringLength, comparison); return result; } private static int? FindIndexByName(string[] enumNames, string value, int valueIndex, int valueSubstringLength, StringComparison comparison) { for (int i = 0; i < enumNames.Length; i++) { if (enumNames[i].Length == valueSubstringLength && string.Compare(enumNames[i], 0, value, valueIndex, valueSubstringLength, comparison) == 0) return i; } return null; } } }