Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves System.Enum compatibility #12

Merged
merged 20 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This library super easy to use like `System.Enum` that is standard of .NET. Look
var values = FastEnum.GetValues<Fruits>();
var names = FastEnum.GetNames<Fruits>();
var name = FastEnum.GetName<Fruits>(Fruits.Apple);
var name = Fruits.Apple.ToName();
var name = Fruits.Apple.FastToString();
var defined = FastEnum.IsDefined<Fruits>(123);
var parse = FastEnum.Parse<Fruits>("Apple");
var tryParse = FastEnum.TryParse<Fruits>("Apple", out var value);
Expand Down Expand Up @@ -77,7 +77,7 @@ class Member<TEnum>
// etc...
}

var member = Fruits.Apple.ToMember();
var member = Fruits.Apple.ToMember()!;
var (name, value) = member; // Supports deconstruction
```

Expand Down
3 changes: 2 additions & 1 deletion src/Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
typeof(IsDefinedByteBenchmark),
typeof(IsDefinedEnumBenchmark),
typeof(IsDefinedStringBenchmark),
typeof(ToStringBenchmark),
typeof(ToStringDefinedBenchmark),
typeof(ToStringUndefinedBenchmark),
typeof(DictionaryEnumKeyBenchmark),
typeof(DictionaryInt32KeyBenchmark),
typeof(DictionaryStringKeyBenchmark),
Expand Down
2 changes: 1 addition & 1 deletion src/Benchmarks/Scenarios/GetNameBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ public void Setup()


[Benchmark]
public string FastEnum()
public string? FastEnum()
=> _FastEnum.GetName(Value);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using BenchmarkDotNet.Attributes;
using EnumsNET;
using FastEnumUtility.Benchmarks.Models;
using _FastEnum = FastEnumUtility.FastEnum;

namespace FastEnumUtility.Benchmarks.Scenarios;



public class ToStringBenchmark
public class ToStringDefinedBenchmark
{
private const Fruits Value = Fruits.Pineapple;

Expand All @@ -16,7 +17,8 @@ public class ToStringBenchmark
public void Setup()
{
_ = Enum.GetNames<Fruits>();
_ = _FastEnum.GetValues<Fruits>();
_ = Enums.GetNames<Fruits>();
_ = _FastEnum.GetMembers<Fruits>();
}


Expand All @@ -25,7 +27,12 @@ public string NetCore()
=> Value.ToString();


[Benchmark]
public string EnumsNet()
=> Value.AsString();


[Benchmark]
public string FastEnum()
=> Value.ToName();
=> Value.FastToString();
}
38 changes: 38 additions & 0 deletions src/Benchmarks/Scenarios/ToStringUndefinedBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using BenchmarkDotNet.Attributes;
using EnumsNET;
using FastEnumUtility.Benchmarks.Models;
using _FastEnum = FastEnumUtility.FastEnum;

namespace FastEnumUtility.Benchmarks.Scenarios;



public class ToStringUndefinedBenchmark
{
private const Fruits Value = (Fruits)byte.MaxValue; // undefined value


[GlobalSetup]
public void Setup()
{
_ = Enum.GetNames<Fruits>();
_ = Enums.GetNames<Fruits>();
_ = _FastEnum.GetMembers<Fruits>();
}


[Benchmark(Baseline = true)]
public string NetCore()
=> Value.ToString();


[Benchmark]
public string EnumsNet()
=> Value.AsString();


[Benchmark]
public string FastEnum()
=> Value.FastToString();
}
31 changes: 25 additions & 6 deletions src/FastEnum/FastEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ public static IReadOnlyList<string> GetNames<T>()


/// <summary>
/// Retrieves the name of the constants in a specified enumeration.
/// Retrieves the name of the constant in the specified enumeration type that has the specified value.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <returns></returns>
/// <param name="value"></param>
/// <returns>A string containing the name of the enumerated constant in enumType whose value is value; or null if no such constant is found.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetName<T>(T value)
public static string? GetName<T>(T value)
where T : struct, Enum
=> GetMember(value).Name;
=> GetMember(value)?.Name;
#endregion


Expand All @@ -81,11 +82,15 @@ public static IReadOnlyList<Member<T>> GetMembers<T>()
/// Retrieves the member information of the constants in a specified enumeration.
/// </summary>
/// <typeparam name="T">Enum type</typeparam>
/// <param name="value"></param>
/// <returns></returns>
/// <exception cref="NotFoundException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Member<T> GetMember<T>(T value)
public static Member<T>? GetMember<T>(T value)
where T : struct, Enum
=> Cache_UnderlyingOperation<T>.UnderlyingOperation.GetMember(ref value);
=> Cache_UnderlyingOperation<T>.UnderlyingOperation.TryGetMember(ref value, out var member)
? member
: null;
#endregion


Expand Down Expand Up @@ -309,4 +314,18 @@ private static bool TryParseName<T>(string name, bool ignoreCase, out T result)
return false;
}
#endregion


#region ToString
/// <summary>
/// Converts the specified value to its equivalent string representation.
/// </summary>
/// <param name="value"></param>
/// <typeparam name="T">Enum type</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToString<T>(T value)
where T : struct, Enum
=> Cache_UnderlyingOperation<T>.UnderlyingOperation.ToString(ref value);
#endregion
}
56 changes: 43 additions & 13 deletions src/FastEnum/FastEnumExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static partial class FastEnumExtensions
/// <param name="value"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Member<T> ToMember<T>(this T value)
public static Member<T>? ToMember<T>(this T value)
where T : struct, Enum
=> FastEnum.GetMember(value);

Expand All @@ -28,13 +28,25 @@ public static Member<T> ToMember<T>(this T value)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <returns></returns>
/// <returns>A string containing the name of the enumerated constant in enumType whose value is value; or null if no such constant is found.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string ToName<T>(this T value)
public static string? ToName<T>(this T value)
where T : struct, Enum
=> FastEnum.GetName(value);


/// <summary>
/// Converts the specified value to its equivalent string representation.
/// </summary>
/// <param name="value"></param>
/// <typeparam name="T">Enum type</typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string FastToString<T>(this T value)
where T : struct, Enum
=> FastEnum.ToString(value);


/// <summary>
/// Returns an indication whether a constant with a specified value exists in a specified enumeration.
/// </summary>
Expand All @@ -54,17 +66,27 @@ public static bool IsDefined<T>(this T value)
/// <param name="value"></param>
/// <param name="throwIfNotFound"></param>
/// <returns></returns>
/// <exception cref="NotFoundException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string? GetEnumMemberValue<T>(this T value, bool throwIfNotFound = true)
where T : struct, Enum
{
var attr = value.ToMember().EnumMemberAttribute;
if (attr is not null)
return attr.Value;
var member = value.ToMember();
if (throwIfNotFound)
{
if (member is null)
throw new NotFoundException($"Specified value {value} is not defined.");

return throwIfNotFound
? throw new NotFoundException($"{nameof(EnumMemberAttribute)} is not found.")
: default;
var attr = member.EnumMemberAttribute;
if (attr is null)
throw new NotFoundException($"{nameof(EnumMemberAttribute)} is not found.");

return attr.Value;
}
else
{
return member?.EnumMemberAttribute?.Value;
}
}


Expand All @@ -76,6 +98,8 @@ public static bool IsDefined<T>(this T value)
/// <param name="index"></param>
/// <param name="throwIfNotFound"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="NotFoundException"></exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string? GetLabel<T>(this Member<T> member, int index = 0, bool throwIfNotFound = true)
where T : struct, Enum
Expand All @@ -86,9 +110,10 @@ public static bool IsDefined<T>(this T value)
if (member.Labels.TryGetValue(index, out var label))
return label;

return throwIfNotFound
? throw new NotFoundException($"{nameof(LabelAttribute)} that is specified index {index} is not found.")
: default;
if (throwIfNotFound)
throw new NotFoundException($"{nameof(LabelAttribute)} that is specified index {index} is not found.");

return null;
}


Expand All @@ -103,5 +128,10 @@ public static bool IsDefined<T>(this T value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string? GetLabel<T>(this T value, int index = 0, bool throwIfNotFound = true)
where T : struct, Enum
=> value.ToMember().GetLabel(index, throwIfNotFound);
{
var member = value.ToMember();
if (throwIfNotFound && member is null)
throw new NotFoundException($"Specified value {value} is not defined.");
return member?.GetLabel(index, throwIfNotFound);
}
}