DotNext by Roman Sakno

<PackageReference Include="DotNext" Version="1.2.6" />

 Enum<E>

public struct Enum<E> : IEquatable<E>, IComparable<E>, IFormattable, IEquatable<Enum<E>>, ISerializable where E : struct, Enum
Provides strongly typed way to reflect enum type.
using DotNext.Runtime; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; namespace DotNext { [Serializable] public readonly struct Enum<E> : IEquatable<E>, IComparable<E>, IFormattable, IEquatable<Enum<E>>, ISerializable where E : struct, Enum { private readonly struct Tuple : IEquatable<Tuple> { internal readonly string Name; internal readonly E Value; private Tuple(string name) { Name = name; Value = default(E); } private Tuple(E value) { Value = value; Name = null; } public static implicit operator Tuple(string name) { return new Tuple(name); } public static implicit operator Tuple(E value) { return new Tuple(value); } public bool Equals(Tuple other) { if (Name != null) return Name == other.Name; if (other.Name == null) return EqualityComparer<E>.Default.Equals(Value, other.Value); return false; } public override bool Equals(object other) { if (other is Tuple) { Tuple other2 = (Tuple)other; return Equals(other2); } return false; } public override int GetHashCode() { if (Name != null) return Name.GetHashCode(); return Value.GetHashCode(); } } private sealed class Mapping : Dictionary<Tuple, long> { internal readonly Enum<E>[] Members; internal Enum<E> this[string name] { get { return Members[base[name]]; } } internal Mapping(out Enum<E> min, out Enum<E> max) { string[] names = Enum.GetNames(typeof(E)); E[] array = (E[])Enum.GetValues(typeof(E)); Members = new Enum<E>[names.LongLength]; min = (max = default(Enum<E>)); for (long num = 0; num < names.LongLength; num++) { Enum<E> enum = Members[num] = new Enum<E>(array[num], names[num]); Add(enum.Name, num); base[enum.Value] = num; E value = enum.Value; min = ((value.CompareTo(min.Value) < 0) ? enum : min); value = enum.Value; max = ((value.CompareTo(max.Value) > 0) ? enum : max); } } internal bool TryGetValue(E value, out Enum<E> member) { if (TryGetValue(value, out long value2)) { member = Members[value2]; return true; } member = default(Enum<E>); return false; } } private static readonly Mapping mapping = new Mapping(out MinValue, out MaxValue); public static readonly Enum<E> MaxValue; public static readonly Enum<E> MinValue; private const string NameSerData = "Name"; private const string ValueSerData = "Value"; private readonly string name; public static IReadOnlyList<Enum<E>> Members => mapping.Members; public static Type UnderlyingType => Enum.GetUnderlyingType(typeof(E)); public static TypeCode UnderlyingTypeCode => Type.GetTypeCode(typeof(E)); public E Value { get; } public string Name => name ?? ValueTypeExtensions.ToString<E>(Value, (IFormatProvider)null); public static bool IsDefined(E value) { return mapping.ContainsKey(value); } public static bool IsDefined(string name) { return mapping.ContainsKey(name); } public static Enum<E> GetMember(E value) { if (!mapping.TryGetValue(value, out Enum<E> member)) return new Enum<E>(value, null); return member; } public static bool TryGetMember(E value, out Enum<E> member) { return mapping.TryGetValue(value, out member); } public static bool TryGetMember(string name, out Enum<E> member) { if (Enum.TryParse<E>(name, out E result)) { member = new Enum<E>(result, name); return true; } member = default(Enum<E>); return false; } public static Enum<E> GetMember(string name) { return mapping[name]; } private Enum(E value, string name) { Value = value; this.name = name; } private Enum(SerializationInfo info, StreamingContext context) { name = info.GetString("Name"); Value = (E)info.GetValue("Value", typeof(E)); } public bool HasFlag(E flag) { return Intrinsics.HasFlag<E>(Value, flag); } public static implicit operator E([In] [System.Runtime.CompilerServices.IsReadOnly] ref Enum<E> en) { return en.Value; } public int CompareTo(E other) { return Comparer<E>.Default.Compare(Value, other); } public bool Equals(E other) { return EqualityComparer<E>.Default.Equals(Value, other); } public bool Equals(Enum<E> other) { if (Equals(other.Value)) return object.Equals(Name, other.Name); return false; } public override bool Equals(object other) { if (other is Enum<E>) { Enum<E> other2 = (Enum<E>)other; return Equals(other2); } if (other is E) { E other3 = (E)other; return Equals(other3); } return false; } public override int GetHashCode() { return (-1670801664 * -1521134295 + Value.GetHashCode()) * -1521134295 + Name.GetHashCode(); } public override string ToString() { return ValueTypeExtensions.ToString<E>(Value, (IFormatProvider)null); } string IFormattable.ToString(string format, IFormatProvider provider) { return ValueTypeExtensions.ToString<E>(Value, format, provider); } public static bool operator ==(Enum<E> first, Enum<E> second) { return first.Equals(second); } public static bool operator !=(Enum<E> first, Enum<E> second) { return !first.Equals(second); } void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("Name", name, typeof(string)); info.AddValue("Value", Value); } } }