简体   繁体   中英

Compare two System.Enum of type T

I am pretty close to understand Generics now (I think).
However, just figured that System.Enum is not easy to implement as a generic type. I have this class:

public class Button<TEnum> where TEnum : struct, IConvertible, IComparable, IFormattable {
   public TEnum Identifier {
        get;
        private set; //Set in the ctor
    }
}

and

public abstract class AbstractInputDevice<TEnum> where TEnum : struct, IConvertible, IComparable, IFormattable {

   private List<Button<TEnum>> _buttons = new List<Button<TEnum>>();

   public Button<TEnum> GetButton(TEnum Identifier){
        foreach(Button<TEnum> button in _buttons){
            if(button.Identifier == Identifier) //<- compiler throws
                return button;
        }
        Debug.Log("'" + GetType().Name + "' cannot return an <b>unregistered</b> '" + typeof(Button<TEnum>).Name + "' that listens to '" + typeof(TEnum).Name + "." + Identifier.ToString() + "'.");
        return null;
    }
}

An InputDevice might look like that:

public class Keyboard : AbstractInputDevice<KeyCode> {
    private void Useless(){
        Button<KeyCode> = GetButton(KeyCode.A);
    }
}

The compiler throws a compile error right here:

if(button.Identifier == Identifier) //In AbstractInputDevice above

I believe I cannot compare these two TEnums because they are not actually known to be Enums.
And thus no comparison method is available.

I used this resource:
Create Generic method constraining T to an Enum

I appreciate any better solution or fix.
(But I want to keep the Enum entry as a parameter to GetButton(EnumEntry) )

Instead of the impossible

button.Identifier == Identifier

you should use

EqualityComparer<TEnum>.Default.Equals(button.Identifier, Identifier)

This avoids boxing the value into an object box (or IComparable box).

You are trying to perform a reference comparison on a value type (struct), use Equals for equality instead:

public Button<TEnum> GetButton(TEnum Identifier) {
    var button = _buttons
        .Where(b => EqualityComparer<TEnum>.Default.Equals(b.Identifier, Identifier))
        .FirstOrDefault();

    if (button == null)
        Debug.Log("'" + GetType().Name + "' cannot return an <b>unregistered</b> '" + typeof(Button<TEnum>).Name + "' that listens to '" + typeof(TEnum).Name + "." + Identifier.ToString() + "'.");
    return button;
}

The button.Identifier == Identifier statement cannot be performed, because the == operator does not exist for structs. On a class it would have performed a reference comparison.

And as @JeppeStigNielsen noted in his answer , to prevent a boxing equality comparison, it is better to use the EqualityComparer<TEnum>.Default.Equals method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM