泛型<TEnum>类中不同枚举类型的比较问题
实现支持跨枚举类型比较的SmartEnum包装类
我需要构建一个能存储任意枚举的包装类SmartEnum<TEnum>,要求它可以比较不同枚举类型的包装实例。当前实现的Equals方法仅支持同类型枚举包装实例的比较,当比较不同枚举类型的实例时,会默认调用object.Equals。试过多种泛型重载都没解决,求可行的改进方案。
当前代码实现
public class SmartEnum<TEnum> where TEnum : System.Enum { public TEnum Enum; public SmartEnum(TEnum Enum) { this.Enum = Enum; } public bool Equals(SmartEnum<TEnum> smartEnum) { var aType = Enum.GetType(); var bType = smartEnum.Enum.GetType(); if(aType != bType) return false; return (int)(object)(Enum) == (int)(object)(smartEnum.Enum); } }
问题复现代码
SmartEnum<Color> red = new SmartEnum<Color>(Color.RED); SmartEnum<Color> green = new SmartEnum<Color>(Color.GREEN); SmartEnum<Car> car = new SmartEnum<Car>(Car.SUZUKI); red.Equals(green); // 正常工作 red.Equals(car); // 实际调用object.Equals
尝试的重载方案及错误
- 方案代码:
public bool Equals<T>(T smartEnum) where T : SmartEnum<TEnum>
错误信息:
The type 'SmartEnum<SmartEnumTestUnit.Car>' cannot be used as type parameter 'T' in the generic type or method 'SmartEnum<SmartEnumTestUnit.Color>.Equals<T>(T)'. There is no implicit reference conversion from 'SmartEnum<SmartEnumTestUnit.Car>' to 'SmartEnum<SmartEnumTestUnit.Color>'
- 方案代码:
public bool Equals<SmartEnum>(SmartEnum<TEnum> smartEnum) where SmartEnum : SmartEnum<TEnum>
结果:仍默认调用object.Equals
- 方案代码:
public bool Equals<T>(T smartEnum) where T : TEnum
错误信息:
red.Equals<Car>(car) The type 'SmartEnumTestUnit.Car' cannot be used as type parameter 'T' in the generic type or method 'SmartEnum<SmartEnumTestUnit.Color>.Equals<T>(T)'. There is no boxing conversion from 'SmartEnumTestUnit.Car' to 'SmartEnumTestUnit.Color'.
解决方案
要实现跨枚举类型的比较,核心是重写object.Equals(object obj)方法,在方法内部兼容任意泛型参数的SmartEnum实例,通过枚举的底层类型和数值进行比较。改进后的代码如下:
public class SmartEnum<TEnum> where TEnum : System.Enum { public TEnum Value { get; } public SmartEnum(TEnum value) { Value = value; } // 同类型强类型比较,保证性能 public bool Equals(SmartEnum<TEnum> other) { if (other is null) return false; return EqualityComparer<TEnum>.Default.Equals(Value, other.Value); } // 重写object.Equals,处理跨类型比较 public override bool Equals(object obj) { // 先处理同类型实例 if (obj is SmartEnum<TEnum> sameTypeEnum) { return Equals(sameTypeEnum); } // 处理不同类型的SmartEnum实例 if (obj is SmartEnum<dynamic> otherEnum) { var thisUnderlyingType = Enum.GetUnderlyingType(typeof(TEnum)); var otherUnderlyingType = Enum.GetUnderlyingType(otherEnum.Value.GetType()); // 底层类型不同直接返回false if (thisUnderlyingType != otherUnderlyingType) return false; // 转换为相同底层类型后比较数值 var thisValue = Convert.ChangeType(Value, thisUnderlyingType); var otherValue = Convert.ChangeType(otherEnum.Value, thisUnderlyingType); return EqualityComparer<object>.Default.Equals(thisValue, otherValue); } return false; } // 重写GetHashCode,与Equals逻辑保持一致 public override int GetHashCode() { var underlyingType = Enum.GetUnderlyingType(typeof(TEnum)); var value = Convert.ChangeType(Value, underlyingType); return value.GetHashCode(); } // 可选:重载==和!=运算符 public static bool operator ==(SmartEnum<TEnum> left, SmartEnum<TEnum> right) { return Equals(left, right); } public static bool operator !=(SmartEnum<TEnum> left, SmartEnum<TEnum> right) { return !Equals(left, right); } }
关键说明
- 将原字段
Enum重命名为Value,避免与系统类型Enum冲突,符合C#命名规范。 - 保留强类型
Equals方法用于同类型比较,避免不必要的类型转换开销。 - 在
object.Equals中,通过dynamic兼容任意泛型参数的SmartEnum,先判断枚举底层类型是否一致,再转换为底层类型比较数值。 - 重写
GetHashCode确保哈希值计算逻辑与Equals一致,避免在哈希集合中出现不一致的情况。
测试验证
// 假设Color.RED底层值为0,Car.SUZUKI底层值为0,且两者底层类型都是int SmartEnum<Color> red = new SmartEnum<Color>(Color.RED); SmartEnum<Car> suzuki = new SmartEnum<Car>(Car.SUZUKI); Console.WriteLine(red.Equals(suzuki)); // 输出True Console.WriteLine(red.Equals(new SmartEnum<Color>(Color.GREEN))); // 输出False
内容的提问来源于stack exchange,提问作者P. BG
相关产品推荐
相关产品推荐

