[英]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()
解決方法,但它對關系運算符沒有幫助)。
所以,兩個問題:
IComparable
的泛型類型的值? 它不會以某種方式擊敗通用約束的整個目的嗎?(我意識到已經有一些與這個看似簡單的問題相關的問題 - 但沒有一個線程給出詳盡或可行的答案,所以在這里。)
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
- 編輯 -
我能夠通過限制清理它T
到IComparable(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.