2012-09-24 52 views
1

可能重複:
When are two enums equal in C#?IComparable的與枚舉發送作爲一般類型參數(C#)

我有以下的類作爲一個簡單的狀態機的一部分。

請注意,所有泛型類型參數都必須是枚舉。這已經在構造函數中執行(未在此處顯示)。

// Both [TState] and [TCommand] will ALWAYS be enumerations. 
public class Transitions<TState, TCommand>: List<Transition<TState, TCommand>> 
{ 
    public new void Add (Transition<TState, TCommand> item) 
    { 
     if (this.Contains(item)) 
      throw (new InvalidOperationException("This transition already exists.")); 
     else 
      this.Add(item); 
    } 
} 

// Both [TState] and [TCommand] will ALWAYS be enumerations. 
public class Transition<TState, TCommand> 
{ 
    TState From = default(TState); 
    TState To = default(TState); 
    TCommand Command = default(TCommand); 
} 

public sealed class TransitionComparer<TState>: 
    IComparer<TState> 
{ 
    public int Compare (TState x, TState y) 
    { 
     int result = 0; 

     // How to compare here since TState is not strongly typed and is an enum? 
     // Using ToString seems silly here. 

     result |= x.From.ToString().CompareTo(y.From.ToString()); 
     result |= x.To.ToString().CompareTo(y.To.ToString()); 
     result |= x.Command.ToString().CompareTo(y.Command.ToString()); 

     return (result); 
    } 
} 

上述聲明編譯,但我不知道這是否是處理已經在爲泛型類型參數已經通過枚舉的正確途徑。

注意:比較功能不需要記住排序。相反,它需要檢查確切的重複。

回答

3

注意:比較功能不需要考慮排序。相反,它需要檢查確切的重複。

在這種情況下,您不應該執行IComparer<T>。您應該實施IEqualityComparer<T> - 或者更簡單地說,使Transition實施IEquatable<Transition>

請注意,您目前沒有使用TransitionComparer在代碼的其餘部分使用,就我們所見。這聽起來像你不應該真的需要爲每個枚舉值編寫自己的比較代碼 - 你只是想把它們結合起來。不幸的是枚舉不實現IEquatable<T>,這使得沒有裝箱就更難了 - 這對性能至關重要嗎?

下面是Transition樣本平等的實現:

public class Transition<TState, TCommand> 
    : IEquatable<Transition<TState, TCommand>> 
{ 
    // I assume in reality these are properties? 
    TState From = default(TState); 
    TState To = default(TState); 
    TCommand Command = default(TCommand); 

    public override bool Equals(object other) 
    { 
     return Equals(other as Transition<TState, TCommand>); 
    } 

    public bool Equals(Transition<TState, TCommand> other) 
    { 
     if (other == null) 
     { 
      return false; 
     } 
     return From.Equals(other.From) && 
       To.Equals(other.To) && 
       Command.Equals(other.Command); 
    } 

    public int GetHashCode() 
    { 
     int hash = 17; 
     hash = hash * 31 + From.GetHashCode(); 
     hash = hash * 31 + To.GetHashCode(); 
     hash = hash * 31 + Command.GetHashCode(); 
     return hash; 
    } 
} 

編輯:爲了避免拳擊平等的,我懷疑你會要麼需要某種形式的委託來獲得的潛在價值(如果你需要以支持具有不同基礎類型的值,這非常痛苦)可能使用類似Unconstrained Melody的東西,它使用IL重寫在編譯時強制執行約束,並允許您更有效地檢查基於基礎值的相等性。

+0

謝謝。我將此作爲未來項目的圖書館編寫,其中一些可能對性能至關重要。你會在這種情況下采取任何不同的方式嗎?是的,你是對的,比較器本身沒有被使用在任何地方。 –

+0

@RaheelKhan:我會添加一個修改。 –

+0

感謝Jon,糾正我的錯誤,實現並鏈接到UM!與此同時,我將用拳擊原型並觀察UM。 –

0

我看不到任何東西比

(int)(object)x.From.CompareTo((int)(object)y.From); 

的枚舉被裝箱。我不知道這是如何避免的。

+0

這是假設,我們知道的基本類型是'int',當然這種方法。 –

+0

是的。但仍然可能在特定項目中工作。它不會是框架代碼。 –

+0

它可能確實有效 - 我認爲這值得注意。 –