Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions src/SmartEnum/SmartFlagEnum.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Ardalis.SmartEnum.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using Ardalis.SmartEnum.Core;

namespace Ardalis.SmartEnum
{
Expand Down Expand Up @@ -43,13 +43,16 @@ public abstract class SmartFlagEnum<TEnum, TValue> :
where TEnum : SmartFlagEnum<TEnum, TValue>
where TValue : IEquatable<TValue>, IComparable<TValue>
{
static readonly Lazy<List<TEnum>> _enumOptions =
new Lazy<List<TEnum>>(GetAllOptions, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication);

static readonly Lazy<Dictionary<string, TEnum>> _fromName =
new Lazy<Dictionary<string, TEnum>>(() => GetAllOptions().ToDictionary(item => item.Name));
new Lazy<Dictionary<string, TEnum>>(() => _enumOptions.Value.ToDictionary(item => item.Name));

static readonly Lazy<Dictionary<string, TEnum>> _fromNameIgnoreCase =
new Lazy<Dictionary<string, TEnum>>(() => GetAllOptions().ToDictionary(item => item.Name, StringComparer.OrdinalIgnoreCase));
new Lazy<Dictionary<string, TEnum>>(() => _enumOptions.Value.ToDictionary(item => item.Name, StringComparer.OrdinalIgnoreCase));

private static IEnumerable<TEnum> GetAllOptions()
private static List<TEnum> GetAllOptions()
{
Type baseType = typeof(TEnum);
IEnumerable<Type> enumTypes = Assembly.GetAssembly(baseType).GetTypes().Where(t => baseType.IsAssignableFrom(t));
Expand All @@ -61,7 +64,7 @@ private static IEnumerable<TEnum> GetAllOptions()
options.AddRange(typeEnumOptions);
}

return options.OrderBy(t => t.Value);
return options.OrderBy(t => t.Value).ToList();
}

/// <summary>
Expand All @@ -70,9 +73,7 @@ private static IEnumerable<TEnum> GetAllOptions()
/// <value>A <see cref="IReadOnlyCollection{TEnum}"/> containing all the instances of <see cref="SmartFlagEnum{TEnum, TValue}"/>.</value>
/// <remarks>Retrieves all the instances of <see cref="SmartFlagEnum{TEnum, TValue}"/> referenced by public static read-only fields in the current class or its bases.</remarks>
public static IReadOnlyCollection<TEnum> List =>
_fromName.Value.Values
.ToList()
.AsReadOnly();
_enumOptions.Value;

private readonly string _name;
private readonly TValue _value;
Expand Down Expand Up @@ -190,12 +191,12 @@ public static IEnumerable<TEnum> 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<TEnum, TValue>(value);
}

return GetFlagEnumValues(value, GetAllOptions());
return GetFlagEnumValues(value, _enumOptions.Value);
}

/// <summary>
Expand All @@ -206,10 +207,7 @@ public static IEnumerable<TEnum> FromValue(TValue value)
/// <returns></returns>
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)
{
Expand Down Expand Up @@ -257,7 +255,7 @@ public static bool TryFromValue(TValue value, out IEnumerable<TEnum> result)
}


result = GetFlagEnumValues(value, GetAllOptions());
result = GetFlagEnumValues(value, _enumOptions.Value);
if (result is null)
{
return false;
Expand All @@ -277,7 +275,7 @@ public static string FromValueToString(TValue value)
ThrowHelper.ThrowValueNotFoundException<TEnum, TValue>(value);
}

return FormatEnumListString(GetFlagEnumValues(value, GetAllOptions()));
return FormatEnumListString(GetFlagEnumValues(value, _enumOptions.Value));
}

/// <summary>
Expand Down
13 changes: 9 additions & 4 deletions src/SmartEnum/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand All @@ -7,11 +8,15 @@ namespace Ardalis.SmartEnum;

internal static class TypeExtensions
{
private static readonly ConcurrentDictionary<Type, object> FieldCache = new();
public static List<TFieldType> GetFieldsOfType<TFieldType>(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<TFieldType>)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();
});
}
}