Search code examples
c#genericsenumswrapper

Comparing different Enums in generic <TEnum> class


I am trying to build a wrapper class to store any enum. It should then be able to compare 2 different wrapper of different enum types.

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);
    }
}

The problem is that when I call the Equals method on enum A and pass enum B it defauls to using object.Equals instead:

    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); <-- Works
    red.Equals(car) <-- Actually calls object.Equals

I understand that because SmartEnum is generic and Equals is not, it expects to receive the same type as the class instance.

If anyone knows how to do it or has a better way to compare different enums I would appreciate it :)

I tried to play around making it Equals<SmartEnum> or Equals<T> and use "where TEnum : SmartEnum but I can't seem to wrap my head around how to make this work:

1.

public bool Equals<T>(T smartEnum) where T : SmartEnum<TEnum>

This results in:

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>

This results in defaulting to object.Equals

3.

public bool Equals<T>(T smartEnum) where T : TEnum

Finally results in:

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'.

Solution

  • Not sure why you want to do this, but one of the attempts was quite close, purely from technical perspective try the following:

    public bool Equals<T>(SmartEnum<T> smartEnum) where T:Enum
    {
        // ...
    }
    

    This declares Equals with generic parameter T which should be enum and restricts the incoming smartEnum parameter to SmartEnum<T>.

    Note that T here just a generic parameter name, as SmartEnum in:

    public bool Equals<SmartEnum>(SmartEnum<TEnum> smartEnum) where SmartEnum : SmartEnum<TEnum>
    

    Which results in quite interesting behavior here due to names matching (SmartEnum in Equals<SmartEnum> and where SmartEnum : is parameter name, SmartEnum in SmartEnum<TEnum> smartEnum and : SmartEnum<T is the enclosing generic type)

    But in general you might want to override object.Equals(object) and possibly implement IEquatable<SmartEnum<TEnum>>.