mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-22 05:42:53 +00:00
Improved EnumConverter initialization performance
This commit is contained in:
@@ -67,25 +67,14 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
#endif
|
#endif
|
||||||
: JsonConverter<T>, INullableConverterFactory where T : struct, Enum
|
: JsonConverter<T>, INullableConverterFactory where T : struct, Enum
|
||||||
{
|
{
|
||||||
class EnumMapping
|
|
||||||
{
|
|
||||||
public T Value { get; set; }
|
|
||||||
public string StringValue { get; set; }
|
|
||||||
|
|
||||||
public EnumMapping(T value, string stringValue)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
StringValue = stringValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if NET8_0_OR_GREATER
|
#if NET8_0_OR_GREATER
|
||||||
private static FrozenSet<EnumMapping>? _mappingToEnum = null;
|
private static FrozenDictionary<string, T>? _mappingToEnum = null;
|
||||||
private static FrozenDictionary<T, string>? _mappingToString = null;
|
private static FrozenDictionary<T, string>? _mappingToString = null;
|
||||||
|
|
||||||
private static bool RunOptimistic => true;
|
private static bool RunOptimistic => true;
|
||||||
#else
|
#else
|
||||||
private static List<EnumMapping>? _mappingToEnum = null;
|
private static Dictionary<string, T>? _mappingToEnum = null;
|
||||||
private static Dictionary<T, string>? _mappingToString = null;
|
private static Dictionary<T, string>? _mappingToString = null;
|
||||||
|
|
||||||
// In NetStandard the `ValueTextEquals` method used is slower than just string comparing
|
// In NetStandard the `ValueTextEquals` method used is slower than just string comparing
|
||||||
@@ -205,7 +194,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (!_unknownValuesWarned.Contains(stringValue))
|
if (!_unknownValuesWarned.Contains(stringValue))
|
||||||
{
|
{
|
||||||
_unknownValuesWarned.Add(stringValue!);
|
_unknownValuesWarned.Add(stringValue!);
|
||||||
LibraryHelpers.StaticLogger?.LogWarning($"Cannot map enum value. EnumType: {_enumType.FullName}, Value: {stringValue}, Known values: [{string.Join(", ", _mappingToEnum!.Select(m => $"{m.StringValue}: {m.Value}"))}]. If you think {stringValue} should be added please open an issue on the Github repo");
|
LibraryHelpers.StaticLogger?.LogWarning($"Cannot map enum value. EnumType: {_enumType.FullName}, Value: {stringValue}, Known values: [{string.Join(", ", _mappingToEnum!.Select(m => $"{m.Key}: {m.Value}"))}]. If you think {stringValue} should be added please open an issue on the Github repo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +206,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (!_notOptimalValuesWarned.Contains(stringValue))
|
if (!_notOptimalValuesWarned.Contains(stringValue))
|
||||||
{
|
{
|
||||||
_notOptimalValuesWarned.Add(stringValue!);
|
_notOptimalValuesWarned.Add(stringValue!);
|
||||||
LibraryHelpers.StaticLogger?.LogTrace($"Enum mapping sub-optimal. EnumType: {_enumType.FullName}, Value: {stringValue}, Known values: [{string.Join(", ", _mappingToEnum!.Select(m => $"{m.StringValue}: {m.Value}"))}]");
|
LibraryHelpers.StaticLogger?.LogTrace($"Enum mapping sub-optimal. EnumType: {_enumType.FullName}, Value: {stringValue}, Known values: [{string.Join(", ", _mappingToEnum!.Select(m => $"{m.Key}: {m.Value}"))}]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +241,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
optimisticCheckDone = true;
|
optimisticCheckDone = true;
|
||||||
foreach (var item in _mappingToEnum!)
|
foreach (var item in _mappingToEnum!)
|
||||||
{
|
{
|
||||||
if (reader.ValueTextEquals(item.StringValue))
|
if (reader.ValueTextEquals(item.Key))
|
||||||
return item.Value;
|
return item.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,43 +250,44 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
private static bool GetValue(string value, bool optimisticCheckDone, out T? result)
|
private static bool GetValue(string value, bool optimisticCheckDone, out T? result)
|
||||||
{
|
{
|
||||||
if (_mappingToEnum != null)
|
if (_mappingToEnum == null)
|
||||||
|
throw new InvalidOperationException("Enum mapping not initialized");
|
||||||
|
|
||||||
|
T? mapping = null;
|
||||||
|
// If we tried the optimistic path first we already know its not case match
|
||||||
|
if (!optimisticCheckDone)
|
||||||
{
|
{
|
||||||
EnumMapping? mapping = null;
|
// Try match on full equals
|
||||||
// If we tried the optimistic path first we already know its not case match
|
foreach (var item in _mappingToEnum)
|
||||||
if (!optimisticCheckDone)
|
|
||||||
{
|
{
|
||||||
// Try match on full equals
|
if (item.Key.Equals(value, StringComparison.Ordinal))
|
||||||
foreach (var item in _mappingToEnum)
|
|
||||||
{
|
{
|
||||||
if (item.StringValue.Equals(value, StringComparison.Ordinal))
|
mapping = item.Value;
|
||||||
{
|
break;
|
||||||
mapping = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found, try matching ignoring case
|
|
||||||
if (mapping == null)
|
|
||||||
{
|
|
||||||
foreach (var item in _mappingToEnum)
|
|
||||||
{
|
|
||||||
if (item.StringValue.Equals(value, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
mapping = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapping != null)
|
|
||||||
{
|
|
||||||
result = mapping.Value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If not found, try matching ignoring case
|
||||||
|
if (mapping == null)
|
||||||
|
{
|
||||||
|
foreach (var item in _mappingToEnum)
|
||||||
|
{
|
||||||
|
if (item.Key.Equals(value, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
mapping = item.Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mapping != null)
|
||||||
|
{
|
||||||
|
result = mapping;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (_hasFlagsAttribute)
|
if (_hasFlagsAttribute)
|
||||||
{
|
{
|
||||||
var intValue = int.Parse(value);
|
var intValue = int.Parse(value);
|
||||||
@@ -345,26 +335,21 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
|
|
||||||
private static void CreateMapping()
|
private static void CreateMapping()
|
||||||
{
|
{
|
||||||
var mappingStringToEnum = new List<EnumMapping>();
|
var mappingStringToEnum = new Dictionary<string, T>();
|
||||||
var mappingEnumToString = new Dictionary<T, string>();
|
var mappingEnumToString = new Dictionary<T, string>();
|
||||||
|
|
||||||
#pragma warning disable IL2080
|
#pragma warning disable IL2080
|
||||||
var enumMembers = _enumType.GetFields();
|
var enumMembers = _enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||||
#pragma warning restore IL2080
|
#pragma warning restore IL2080
|
||||||
foreach (var member in enumMembers)
|
foreach (var member in enumMembers)
|
||||||
{
|
{
|
||||||
|
var enumVal = (T)member.GetValue(null)!;
|
||||||
var maps = member.GetCustomAttributes(typeof(MapAttribute), false);
|
var maps = member.GetCustomAttributes(typeof(MapAttribute), false);
|
||||||
foreach (MapAttribute attribute in maps)
|
foreach (MapAttribute attribute in maps)
|
||||||
{
|
{
|
||||||
foreach (var value in attribute.Values)
|
foreach (var value in attribute.Values)
|
||||||
{
|
{
|
||||||
#if NET8_0_OR_GREATER
|
mappingStringToEnum.Add(value, enumVal);
|
||||||
var enumVal = Enum.Parse<T>(member.Name);
|
|
||||||
#else
|
|
||||||
var enumVal = (T)Enum.Parse(_enumType, member.Name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mappingStringToEnum.Add(new EnumMapping(enumVal, value));
|
|
||||||
if (!mappingEnumToString.ContainsKey(enumVal))
|
if (!mappingEnumToString.ContainsKey(enumVal))
|
||||||
mappingEnumToString.Add(enumVal, value);
|
mappingEnumToString.Add(enumVal, value);
|
||||||
}
|
}
|
||||||
@@ -372,7 +357,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if NET8_0_OR_GREATER
|
#if NET8_0_OR_GREATER
|
||||||
_mappingToEnum = mappingStringToEnum.ToFrozenSet();
|
_mappingToEnum = mappingStringToEnum.ToFrozenDictionary();
|
||||||
_mappingToString = mappingEnumToString.ToFrozenDictionary();
|
_mappingToString = mappingEnumToString.ToFrozenDictionary();
|
||||||
#else
|
#else
|
||||||
_mappingToEnum = mappingStringToEnum;
|
_mappingToEnum = mappingStringToEnum;
|
||||||
@@ -411,33 +396,20 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
|||||||
if (_mappingToEnum == null)
|
if (_mappingToEnum == null)
|
||||||
CreateMapping();
|
CreateMapping();
|
||||||
|
|
||||||
EnumMapping? mapping = null;
|
|
||||||
// Try match on full equals
|
// Try match on full equals
|
||||||
foreach(var item in _mappingToEnum!)
|
foreach(var item in _mappingToEnum!)
|
||||||
{
|
{
|
||||||
if (item.StringValue.Equals(value, StringComparison.Ordinal))
|
if (item.Key.Equals(value, StringComparison.Ordinal))
|
||||||
{
|
return item.Value;
|
||||||
mapping = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found, try matching ignoring case
|
// If not found, try matching ignoring case
|
||||||
if (mapping == null)
|
foreach (var item in _mappingToEnum)
|
||||||
{
|
{
|
||||||
foreach (var item in _mappingToEnum)
|
if (item.Key.Equals(value, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
return item.Value;
|
||||||
if (item.StringValue.Equals(value, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
mapping = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapping != null)
|
|
||||||
return mapping.Value;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if NET8_0_OR_GREATER
|
#if NET8_0_OR_GREATER
|
||||||
|
|||||||
Reference in New Issue
Block a user