如何在C#泛型Enum参数中实现高效类型安全的比较操作?
泛型Enum参数无装箱高性能比较方案(.NET 9/C# 13)
针对泛型枚举比较引发的编译错误、子类兼容性及数值类型兼容问题,结合.NET 9的新特性,提供以下几种无装箱、类型安全且高性能的解决方案:
方案1:利用.NET 9新增数值接口约束(推荐)
.NET 9为所有枚举的底层数值类型(含UInt64)实现了INumberBase<T>和IEqualityOperators<T,T,bool>接口,且C# 13允许对枚举类型应用这些接口约束。添加约束后可直接使用==运算符比较,完全无装箱且编译期类型安全。
代码示例
public class FiniteStateMachine<TState, TCommand> where TState : Enum, INumberBase<TState>, IEqualityOperators<TState, TState, bool> where TCommand : Enum, INumberBase<TCommand>, IEqualityOperators<TCommand, TCommand, bool> { public FiniteStateMachine(TState initialState) { // 直接使用==比较,无编译错误且无装箱 if (initialState == default(TState)) { // 自定义处理逻辑 } } } // 子类需继承父类的泛型约束以保证编译通过 public class RouterFiniteStateMachine<TState, TCommand> : FiniteStateMachine<TState, TCommand> where TState : Enum, INumberBase<TState>, IEqualityOperators<TState, TState, bool> where TCommand : Enum, INumberBase<TCommand>, IEqualityOperators<TCommand, TCommand, bool> { public RouterFiniteStateMachine(TState initialState) : base(initialState) { } }
优点
- 代码简洁直观,直接使用原生
==运算符 - 编译期类型校验,避免运行时错误
- 静态绑定运算符调用,性能最优(无装箱、无反射)
方案2:使用EqualityComparer<T>.Default(无需修改泛型约束)
若不想添加额外泛型约束,或子类继承约束存在阻碍,可使用EqualityComparer<T>.Default.Equals方法。.NET中所有枚举会隐式实现IEquatable<TEnum>,该方法会自动调用无装箱的Equals实现,性能接近直接运算符调用。
代码示例
public class FiniteStateMachine<TState, TCommand> where TState : Enum where TCommand : Enum { public FiniteStateMachine(TState initialState) { if (EqualityComparer<TState>.Default.Equals(initialState, default(TState))) { // 自定义处理逻辑 } } } // 子类无需额外约束,直接继承即可编译 public class RouterFiniteStateMachine<TState, TCommand> : FiniteStateMachine<TState, TCommand> where TState : Enum where TCommand : Enum { public RouterFiniteStateMachine(TState initialState) : base(initialState) { } }
优点
- 无需修改泛型约束,子类编译无阻碍
- 无装箱操作,性能优异
- 类型安全,编译期检查参数类型
方案3:通过Unsafe类直接转换底层数值(极致性能)
若追求极致性能,可使用System.Runtime.CompilerServices.Unsafe类将枚举直接转换为底层数值类型比较,完全绕开枚举类型包装,无任何额外开销。
代码示例
先创建静态工具类封装枚举比较逻辑:
public static class EnumComparer<TEnum> where TEnum : Enum { private static readonly Func<TEnum, TEnum, bool> _equalsFunc; static EnumComparer() { var underlyingType = Enum.GetUnderlyingType(typeof(TEnum)); // 根据底层类型创建对应比较委托 _equalsFunc = underlyingType switch { Type t when t == typeof(byte) => (a, b) => Unsafe.As<TEnum, byte>(ref a) == Unsafe.As<TEnum, byte>(ref b), Type t when t == typeof(sbyte) => (a, b) => Unsafe.As<TEnum, sbyte>(ref a) == Unsafe.As<TEnum, sbyte>(ref b), Type t when t == typeof(short) => (a, b) => Unsafe.As<TEnum, short>(ref a) == Unsafe.As<TEnum, short>(ref b), Type t when t == typeof(ushort) => (a, b) => Unsafe.As<TEnum, ushort>(ref a) == Unsafe.As<TEnum, ushort>(ref b), Type t when t == typeof(int) => (a, b) => Unsafe.As<TEnum, int>(ref a) == Unsafe.As<TEnum, int>(ref b), Type t when t == typeof(uint) => (a, b) => Unsafe.As<TEnum, uint>(ref a) == Unsafe.As<TEnum, uint>(ref b), Type t when t == typeof(long) => (a, b) => Unsafe.As<TEnum, long>(ref a) == Unsafe.As<TEnum, long>(ref b), Type t when t == typeof(ulong) => (a, b) => Unsafe.As<TEnum, ulong>(ref a) == Unsafe.As<TEnum, ulong>(ref b), _ => throw new NotSupportedException($"不支持枚举{typeof(TEnum)}的底层类型{underlyingType}") }; } public static bool Equals(TEnum a, TEnum b) => _equalsFunc(a, b); }
在状态机中使用工具类:
public class FiniteStateMachine<TState, TCommand> where TState : Enum where TCommand : Enum { public FiniteStateMachine(TState initialState) { if (EnumComparer<TState>.Equals(initialState, default(TState))) { // 自定义处理逻辑 } } }
优点
- 极致性能,无装箱、无接口调用开销
- 兼容所有底层数值类型(包括
UInt64)
缺点
- 代码相对复杂,需提前初始化比较委托
- 依赖
Unsafe类,需启用unsafe代码或引用System.Runtime.CompilerServices.UnsafeNuGet包
内容的提问来源于stack exchange,提问作者Raheel Khan
相关产品推荐
相关产品推荐

