You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

泛型<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

尝试的重载方案及错误

  1. 方案代码:
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>'
  1. 方案代码:
public bool Equals<SmartEnum>(SmartEnum<TEnum> smartEnum) where SmartEnum : SmartEnum<TEnum>

结果:仍默认调用object.Equals

  1. 方案代码:
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);
    }
}

关键说明

  1. 将原字段Enum重命名为Value,避免与系统类型Enum冲突,符合C#命名规范。
  2. 保留强类型Equals方法用于同类型比较,避免不必要的类型转换开销。
  3. 在object.Equals中,通过dynamic兼容任意泛型参数的SmartEnum,先判断枚举底层类型是否一致,再转换为底层类型比较数值。
  4. 重写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:32:32