Last active
November 25, 2025 05:50
-
-
Save teoadal/95ae4122b547767a7e0f96214912df16 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Frozen; | |
| using System.Collections.Immutable; | |
| using System.Runtime.CompilerServices; | |
| using BenchmarkDotNet.Attributes; | |
| using BenchmarkDotNet.Configs; | |
| using BenchmarkDotNet.Jobs; | |
| using BenchmarkDotNet.Order; | |
| using FastEnumUtility; | |
| namespace Benchmarks; | |
| [SimpleJob(RuntimeMoniker.Net10_0)] | |
| [SimpleJob(RuntimeMoniker.Net90)] | |
| [SimpleJob(RuntimeMoniker.Net80)] | |
| [Orderer(SummaryOrderPolicy.FastestToSlowest)] | |
| [GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByJob)] | |
| [MeanColumn, MemoryDiagnoser] | |
| [HideColumns("Job", "Error", "StdDev", "Median", "RatioSD")] | |
| public class EnumBenchmark | |
| { | |
| private Fruits[] _enumValues = null!; | |
| [Benchmark(Baseline = true)] | |
| public int PureDotnet() | |
| { | |
| var sum = 0; | |
| foreach (var enumValue in _enumValues) | |
| { | |
| var x1 = Enum.GetName(enumValue); | |
| var x2 = Enum.IsDefined(enumValue); | |
| var stringValue = FruitsExtensions.ToString(enumValue); | |
| var x3 = Enum.Parse<Fruits>(stringValue); | |
| sum += Enum.TryParse<Fruits>(stringValue, out var value) | |
| ? HashCode.Combine(x1, x2, x3, value) | |
| : 0; | |
| } | |
| return sum; | |
| } | |
| [Benchmark] | |
| public int PureDotnet_ToString() | |
| { | |
| var sum = 0; | |
| foreach (var enumValue in _enumValues) | |
| { | |
| var x1 = enumValue.ToString(); | |
| var x2 = Enum.IsDefined(enumValue); | |
| var stringValue = FruitsExtensions.ToString(enumValue); | |
| var x3 = Enum.Parse<Fruits>(stringValue); | |
| sum += Enum.TryParse<Fruits>(stringValue, out var value) | |
| ? HashCode.Combine(x1, x2, x3, value) | |
| : 0; | |
| } | |
| return sum; | |
| } | |
| [Benchmark] | |
| public int SelfCode() | |
| { | |
| var sum = 0; | |
| foreach (var enumValue in _enumValues) | |
| { | |
| var x1 = SelfEnumUtils<Fruits>.ToString(enumValue); | |
| var x2 = SelfEnumUtils<Fruits>.IsDefined(enumValue); | |
| var stringValue = FruitsExtensions.ToString(enumValue); | |
| var x3 = SelfEnumUtils<Fruits>.Parse(stringValue); | |
| sum += SelfEnumUtils<Fruits>.TryParse(stringValue, out var value) | |
| ? HashCode.Combine(x1, x2, x3, value) | |
| : 0; | |
| } | |
| return sum; | |
| } | |
| [Benchmark] | |
| public int WithFastEnum() | |
| { | |
| var sum = 0; | |
| foreach (var enumValue in _enumValues) | |
| { | |
| var x1 = FastEnum.ToString<Fruits, FruitsBooster>(enumValue); | |
| var x2 = FastEnum.IsDefined<Fruits, FruitsBooster>(enumValue); | |
| var stringValue = FruitsExtensions.ToString(enumValue); | |
| var x3 = FastEnum.Parse<Fruits, FruitsBooster>(stringValue); | |
| sum += FastEnum.TryParse<Fruits, FruitsBooster>(stringValue, out var value) | |
| ? HashCode.Combine(x1, x2, x3, value) | |
| : 0; | |
| } | |
| return sum; | |
| } | |
| [GlobalSetup] | |
| public void Setup() | |
| { | |
| _enumValues = Enum.GetValues<Fruits>(); | |
| // warmup | |
| Enum.GetValues<Fruits>(); | |
| FastEnum.GetValues<Fruits>(); | |
| SelfEnumUtils<Fruits>.GetValues(); | |
| } | |
| } | |
| [FastEnum<Fruits>] | |
| public partial class FruitsBooster; // code generator will be generated here | |
| public static class FruitsExtensions | |
| { | |
| public static string ToString(this Fruits value) => value switch | |
| { | |
| Fruits.Banana => nameof(Fruits.Banana), | |
| Fruits.Peach => nameof(Fruits.Peach), | |
| Fruits.Orange => nameof(Fruits.Orange), | |
| Fruits.Grape => nameof(Fruits.Grape), | |
| Fruits.Lemon => nameof(Fruits.Lemon), | |
| Fruits.Melon => nameof(Fruits.Melon), | |
| Fruits.Strawberry => nameof(Fruits.Strawberry), | |
| Fruits.Cherry => nameof(Fruits.Cherry), | |
| Fruits.WaterMelon => nameof(Fruits.WaterMelon), | |
| Fruits.Pear => nameof(Fruits.Pear), | |
| Fruits.Pineapple => nameof(Fruits.Pineapple), | |
| _ => value.ToString() | |
| }; | |
| } | |
| public static class SelfEnumUtils<T> | |
| where T : struct, Enum | |
| { | |
| private static readonly FrozenDictionary<string, T> StringToValues; | |
| private static readonly FrozenDictionary<T, string> ValuesToString; | |
| static SelfEnumUtils() | |
| { | |
| var enums = Enum.GetValues<T>(); | |
| var values = new Dictionary<T, string>(enums.Length); | |
| foreach (var value in enums) | |
| { | |
| values.TryAdd(value, value.ToString()); | |
| } | |
| StringToValues = values.ToFrozenDictionary(static value => value.Value, static value => value.Key); | |
| ValuesToString = values.ToFrozenDictionary(); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static ImmutableArray<T> GetValues() => ValuesToString.Keys; | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static bool IsDefined(T value) => ValuesToString.ContainsKey(value); | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static T Parse(string stringValue) => StringToValues.TryGetValue(stringValue, out var value) | |
| ? value | |
| : Throw<T>($"Value '{stringValue}' is not defined"); | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static string ToString(T value) => ValuesToString.TryGetValue(value, out var stringValue) | |
| ? stringValue | |
| : Throw<string>($"Value '{value}' is not defined"); | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static bool TryParse(string stringValue, out T value) => StringToValues.TryGetValue(stringValue, out value); | |
| [MethodImpl(MethodImplOptions.NoInlining)] | |
| private static TResult Throw<TResult>(string message) => throw new Exception(message); | |
| } | |
| public enum Fruits : byte | |
| { | |
| Unknown = 0, | |
| Banana, | |
| Peach, | |
| Orange, | |
| Grape, | |
| Lemon, | |
| Melon, | |
| Strawberry, | |
| Cherry, | |
| WaterMelon, | |
| Pear, | |
| Pineapple, | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment