1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-04-13 00:22:22 +00:00

Added check to EnumConverter for large enums to prevent optimistic checking

This commit is contained in:
Jkorf 2026-04-08 14:52:26 +02:00
parent 4e2dc564dd
commit a955ccbc5c

View File

@ -100,6 +100,8 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
private static ConcurrentBag<string> _unknownValuesWarned = new ConcurrentBag<string>(); private static ConcurrentBag<string> _unknownValuesWarned = new ConcurrentBag<string>();
private static ConcurrentBag<string> _notOptimalValuesWarned = new ConcurrentBag<string>(); private static ConcurrentBag<string> _notOptimalValuesWarned = new ConcurrentBag<string>();
private const int _optimisticValueCountThreshold = 6;
internal class NullableEnumConverter : JsonConverter<T?> internal class NullableEnumConverter : JsonConverter<T?>
{ {
private readonly EnumConverter<T> _enumConverter; private readonly EnumConverter<T> _enumConverter;
@ -165,9 +167,10 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
if (_mappingToEnum == null) if (_mappingToEnum == null)
CreateMapping(); CreateMapping();
bool optimisticCheckDone = false;
if (RunOptimistic) if (RunOptimistic)
{ {
var resultOptimistic = GetValueOptimistic(ref reader); var resultOptimistic = GetValueOptimistic(ref reader, ref optimisticCheckDone);
if (resultOptimistic != null) if (resultOptimistic != null)
return resultOptimistic.Value; return resultOptimistic.Value;
} }
@ -189,7 +192,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
return null; return null;
} }
if (!GetValue(stringValue, out var result)) if (!GetValue(stringValue, optimisticCheckDone, out var result))
{ {
// Note: checking this here and before the GetValue seems redundant but it allows enum mapping for empty strings // Note: checking this here and before the GetValue seems redundant but it allows enum mapping for empty strings
if (string.IsNullOrWhiteSpace(stringValue)) if (string.IsNullOrWhiteSpace(stringValue))
@ -209,7 +212,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
return null; return null;
} }
if (RunOptimistic && !isNumber) if (optimisticCheckDone)
{ {
if (!_notOptimalValuesWarned.Contains(stringValue)) if (!_notOptimalValuesWarned.Contains(stringValue))
{ {
@ -232,11 +235,21 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
/// Try to get the enum value based on the string value using the Utf8JsonReader's ValueTextEquals method. /// Try to get the enum value based on the string value using the Utf8JsonReader's ValueTextEquals method.
/// This is an optimization to avoid string allocations when possible, but can only match case sensitively /// This is an optimization to avoid string allocations when possible, but can only match case sensitively
/// </summary> /// </summary>
private static T? GetValueOptimistic(ref Utf8JsonReader reader) private static T? GetValueOptimistic(ref Utf8JsonReader reader, ref bool optimisticCheckDone)
{ {
if (reader.TokenType != JsonTokenType.String) if (reader.TokenType != JsonTokenType.String)
{
optimisticCheckDone = false;
return null; return null;
}
if (_mappingToEnum!.Count >= _optimisticValueCountThreshold)
{
optimisticCheckDone = false;
return null;
}
optimisticCheckDone = true;
foreach (var item in _mappingToEnum!) foreach (var item in _mappingToEnum!)
{ {
if (reader.ValueTextEquals(item.StringValue)) if (reader.ValueTextEquals(item.StringValue))
@ -246,13 +259,13 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
return null; return null;
} }
private static bool GetValue(string value, out T? result) private static bool GetValue(string value, bool optimisticCheckDone, out T? result)
{ {
if (_mappingToEnum != null) if (_mappingToEnum != null)
{ {
EnumMapping? mapping = null; EnumMapping? mapping = null;
// If we tried the optimistic path first we already know its not case match // If we tried the optimistic path first we already know its not case match
if (!RunOptimistic) if (!optimisticCheckDone)
{ {
// Try match on full equals // Try match on full equals
foreach (var item in _mappingToEnum) foreach (var item in _mappingToEnum)