2015-04-28 14 views
6

Jestem całkiem bliski zrozumienia Generics teraz (myślę).
Jednak uznałem, że System.Enum nie jest łatwy do wdrożenia jako typ ogólny. mam tej klasy:Porównaj dwa System.Enum typu T

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

i

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

InputDevice może wyglądać tak:

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

Kompilator generuje błąd kompilacji prawo tutaj:

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

Uważam, że nie mogę porównać tych dwóch TEnums, ponieważ w rzeczywistości nie są one znane jako Enums.
I dlatego żadna metoda porównania nie jest dostępna.

użyłem tego zasobu:
Create Generic method constraining T to an Enum

Doceniam żadnego lepszego rozwiązania lub poprawki.
(Ale chcę zachować pozycję Enum jako parametr GetButton(EnumEntry))

+2

Jaki jest dokładny błąd dostarczany przez kompilator? –

+1

Możesz chcieć wypróbować 'button.Identifier.Equals (Identifier)', a żeby było bardziej zwięzłe: 'var button = _buttons.Where (b => b.Identifier.Equals (Identifier)). FirstOrDefault();' . – Alex

+0

@RonBeyer Używam Unity3D, a ich kompilator jest czasem trochę zagmatwany. W tej chwili mówi "nieoczekiwany symbol" == "" jak gdyby wystąpił błąd literowy. Ale przed niektórymi zmianami było napisane, że coś innego, jak "" == ", nie może być zastosowane do operandów typu" TEnum "i" TEnum "." –

Odpowiedz

10

Zamiast niemożliwej

button.Identifier == Identifier 

należy użyć

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

ten sposób unika boks wartość w skrzynce object (lub IComparable ramka).

+0

To byłoby lepsze porównanie, uzgodnione – Alex

+0

W porządku, ponieważ Alex zgodził się na to rozwiązanie (już zaznaczyłem jego odpowiedź) Zaznaczę to zamiast tego. –

+0

@NoelWidmer Nadal możesz używać Linq '_buttons.FirstOrDefault (b => EqualityComparer .Default.Equals (b.Identifier, Identifier))" podobnie jak sugeruje Alex, ale to bardziej kwestia stylu i osobistych preferencji. –

1

Próbujesz wykonać porównanie odniesienia na typ wartości (struct), użyj Equals równości zamiast:

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

Nie można wykonać instrukcji button.Identifier == Identifier, ponieważ operator == nie istnieje dla structs. W klasie dokonałby porównania porównawczego.

I jak @JeppeStigNielsen zanotował w swoim numerze answer, aby uniknąć porównania równości boksu, lepiej jest użyć metody EqualityComparer<TEnum>.Default.Equals.

+0

.Equals() działał tak, jak powiedział w komentarzach. Ale nie rozumiem, jak powinienem wdrożyć tę nową linię, którą zamieściłeś w moim oświadczeniu if ... –

+0

@NoelWidmer dodał ją w kontekście oryginalnej metody "GetButton". – Alex

+0

Jest listą . Gdzie jest metoda rozszerzenia?Jeśli tak, czy wiesz, w której przestrzeni nazw się znajduje? (Nie jest rozpoznawana jako członek _przestrzeń) –