diff --git a/src/SmartEnum/SmartFlagEnum.cs b/src/SmartEnum/SmartFlagEnum.cs index d4a01d4f..abce55e3 100644 --- a/src/SmartEnum/SmartFlagEnum.cs +++ b/src/SmartEnum/SmartFlagEnum.cs @@ -1,3 +1,4 @@ +using Ardalis.SmartEnum.Core; using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -5,7 +6,6 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Text; -using Ardalis.SmartEnum.Core; namespace Ardalis.SmartEnum { @@ -43,13 +43,16 @@ public abstract class SmartFlagEnum : where TEnum : SmartFlagEnum where TValue : IEquatable, IComparable { + static readonly Lazy> _enumOptions = + new Lazy>(GetAllOptions, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication); + static readonly Lazy> _fromName = - new Lazy>(() => GetAllOptions().ToDictionary(item => item.Name)); + new Lazy>(() => _enumOptions.Value.ToDictionary(item => item.Name)); static readonly Lazy> _fromNameIgnoreCase = - new Lazy>(() => GetAllOptions().ToDictionary(item => item.Name, StringComparer.OrdinalIgnoreCase)); + new Lazy>(() => _enumOptions.Value.ToDictionary(item => item.Name, StringComparer.OrdinalIgnoreCase)); - private static IEnumerable GetAllOptions() + private static List GetAllOptions() { Type baseType = typeof(TEnum); IEnumerable enumTypes = Assembly.GetAssembly(baseType).GetTypes().Where(t => baseType.IsAssignableFrom(t)); @@ -61,7 +64,7 @@ private static IEnumerable GetAllOptions() options.AddRange(typeEnumOptions); } - return options.OrderBy(t => t.Value); + return options.OrderBy(t => t.Value).ToList(); } /// @@ -70,9 +73,7 @@ private static IEnumerable GetAllOptions() /// A containing all the instances of . /// Retrieves all the instances of referenced by public static read-only fields in the current class or its bases. public static IReadOnlyCollection List => - _fromName.Value.Values - .ToList() - .AsReadOnly(); + _enumOptions.Value; private readonly string _name; private readonly TValue _value; @@ -190,12 +191,12 @@ public static IEnumerable FromValue(TValue value) if (value is null) ThrowHelper.ThrowArgumentNullException(nameof(value)); - if (GetFlagEnumValues(value, GetAllOptions()) is null) + if (GetFlagEnumValues(value, _enumOptions.Value) is null) { ThrowHelper.ThrowValueNotFoundException(value); } - return GetFlagEnumValues(value, GetAllOptions()); + return GetFlagEnumValues(value, _enumOptions.Value); } /// @@ -206,10 +207,7 @@ public static IEnumerable FromValue(TValue value) /// public static TEnum DeserializeValue(TValue value) { - // we should not be calling get options for each deserialization. Perhaps move it to a lazy field _enumOptions. - var enumList = GetAllOptions(); - - var returnValue = enumList.FirstOrDefault(x => x.Value.Equals(value)); + var returnValue = _enumOptions.Value.FirstOrDefault(x => x.Value.Equals(value)); if (returnValue == null) { @@ -257,7 +255,7 @@ public static bool TryFromValue(TValue value, out IEnumerable result) } - result = GetFlagEnumValues(value, GetAllOptions()); + result = GetFlagEnumValues(value, _enumOptions.Value); if (result is null) { return false; @@ -277,7 +275,7 @@ public static string FromValueToString(TValue value) ThrowHelper.ThrowValueNotFoundException(value); } - return FormatEnumListString(GetFlagEnumValues(value, GetAllOptions())); + return FormatEnumListString(GetFlagEnumValues(value, _enumOptions.Value)); } /// diff --git a/src/SmartEnum/TypeExtensions.cs b/src/SmartEnum/TypeExtensions.cs index f3b2f9b1..1d86ed09 100644 --- a/src/SmartEnum/TypeExtensions.cs +++ b/src/SmartEnum/TypeExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -7,11 +8,15 @@ namespace Ardalis.SmartEnum; internal static class TypeExtensions { + private static readonly ConcurrentDictionary FieldCache = new(); public static List GetFieldsOfType(this Type type) { - return type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) - .Where(p => type.IsAssignableFrom(p.FieldType)) - .Select(pi => (TFieldType)pi.GetValue(null)) - .ToList(); + return (List)FieldCache.GetOrAdd(type, t => + { + return t.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) + .Where(p => t.IsAssignableFrom(p.FieldType)) + .Select(pi => (TFieldType)pi.GetValue(null)) + .ToList(); + }); } }