簡體   English   中英

如何比較泛型類型的值?

[英]How to compare values of generic types?

如何比較泛型類型的值?

我已將其縮減為最小樣本:

public class Foo<T> where T : IComparable
{
    private T _minimumValue = default(T);

    public bool IsInRange(T value) 
    {
        return (value >= _minimumValue); // <-- Error here
    }
}

錯誤是:

運算符“>=”不能應用於“T”和“T”類型的操作數。

到底怎么回事!? T已經被限制為IComparable ,即使將它限制為值類型( where T: struct ),我們仍然不能應用任何運算符<><=>===!= (我知道==!=存在涉及Equals()解決方法,但它對關系運算符沒有幫助)。

所以,兩個問題:

  1. 為什么我們會觀察到這種奇怪的行為? 是什么讓我們無法比較已知IComparable的泛型類型的值? 它不會以某種方式擊敗通用約束的整個目的嗎?
  2. 我如何解決這個問題,或者至少解決它?

(我意識到已經有一些與這個看似簡單的問題相關的問題 - 但沒有一個線程給出詳盡或可行的答案,所以在這里。)

IComparable不會重載>=運算符。 你應該使用

value.CompareTo(_minimumValue) >= 0

如果value可以為 null,則當前答案可能會失敗。 使用類似這樣的東西:

Comparer<T>.Default.Compare(value, _minimumValue) >= 0

運算符重載問題

不幸的是,接口不能包含重載運算符。 嘗試在編譯器中輸入:

public interface IInequalityComaparable<T>
{
    bool operator >(T lhs, T rhs);
    bool operator >=(T lhs, T rhs);
    bool operator <(T lhs, T rhs);
    bool operator <=(T lhs, T rhs);
}

我不知道他們為什么不允許這樣做,但我猜這會使語言定義復雜化,並且用戶很難正確實現。

要么如此,要么設計師不喜歡濫用的可能性。 例如,想象對class MagicMrMeow進行>=比較。 甚至在class Matrix<T> 結果對這兩個值意味着什么? 特別是當可能有歧義時?

官方解決辦法

由於上面的接口不合法,我們有IComparable<T>接口來解決這個問題。 它沒有實現任何操作符,並且只公開一種方法, int CompareTo(T other);

請參閱http://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx

int結果實際上是一個三位或三位(類似於Boolean ,但具有三個狀態)。 下表解釋了結果的含義:

Value              Meaning

Less than zero     This object is less than
                   the object specified by the CompareTo method.

Zero               This object is equal to the method parameter.

Greater than zero  This object is greater than the method parameter.

使用變通方法

為了做相當於value >= _minimumValue ,你必須寫:

value.CompareTo(_minimumValue) >= 0
public bool IsInRange(T value) 
{
    return (value.CompareTo(_minimumValue) >= 0);
}

使用 IComparable 泛型時,所有小於/大於運算符都需要轉換為對 CompareTo 的調用。 無論您使用什么運算符,都要以相同的順序比較值,並與零進行比較。 x <op> y變成x.CompareTo(y) <op> 0 ,其中<op>>>=等)

另外,我建議您使用的通用約束是where T : IComparable<T> IComparable 本身意味着對象可以與任何東西進行比較,將一個對象與其他相同類型的對象進行比較可能更合適。

而不是value >= _minimValue使用Comparer類:

public bool IsInRange(T value ) {
    var result = Comparer<T>.Default.Compare(value, _minimumValue);
    if ( result >= 0 ) { return true; }
    else { return false; }
}

正如其他人所說,需要明確使用 CompareTo 方法。 不能使用帶有操作符的接口的原因是一個類可以實現任意數量的接口,而在它們之間沒有明確的排名。 假設有人試圖計算表達式“a = foo + 5;” 當 foo 實現六個接口時,所有接口都定義了一個帶有整數第二個參數的運算符“+”; 操作員應該使用哪個界面?

類可以派生多個接口這一事實使接口非常強大。 不幸的是,它常常迫使人們更加明確自己真正想要做什么。

IComparable僅強制一個名為CompareTo()的函數。 所以你不能應用你提到的任何運營商

我能夠使用 Peter Hedburg 的答案為泛型創建一些重載的擴展方法。 請注意, CompareTo方法在這里不起作用,因為類型T是未知的並且不提供該接口。 也就是說,我有興趣看到任何替代方案。

我想在 C# 中發布,但 Telerik 的轉換器在此代碼上失敗。 我對 C# 不夠熟悉,無法可靠地手動轉換它。 如果有人想獲得榮譽,我很高興看到相應的編輯。

<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T))
  Instance.RemoveDuplicates(Function(X, Y) Comparer(Of T).Default.Compare(X, Y))
End Sub



<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparison As Comparison(Of T))
  Instance.RemoveDuplicates(New List(Of Comparison(Of T)) From {Comparison})
End Sub



<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T)(Instance As List(Of T), Comparisons As List(Of Comparison(Of T)))
  Dim oResults As New List(Of Boolean)

  For i As Integer = 0 To Instance.Count - 1
    For j As Integer = Instance.Count - 1 To i + 1 Step -1
      oResults.Clear()

      For Each oComparison As Comparison(Of T) In Comparisons
        oResults.Add(oComparison(Instance(i), Instance(j)) = 0)
      Next oComparison

      If oResults.Any(Function(R) R) Then
        Instance.RemoveAt(j)
      End If
    Next j
  Next i
End Sub

- 編輯 -

我能夠通過限制清理它TIComparable(Of T)在所有的方法,由OP所示。 請注意,此約束還需要類型T來實現IComparable(Of <type>)

<Extension>
<DebuggerStepThrough>
Public Sub RemoveDuplicates(Of T As IComparable(Of T))(Instance As List(Of T))
  Instance.RemoveDuplicates(Function(X, Y) X.CompareTo(Y))
End Sub

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM