[英]EqualityComparer<T>.Default vs. T.Equals
假設我有一個通用的MyClass<T>
需要比較兩個<T>
類型的對象。 通常我會做類似...
void DoSomething(T o1, T o2)
{
if(o1.Equals(o2))
{
...
}
}
現在假設我的MyClass<T>
有一個支持傳遞自定義IEqualityComparer<T>
的構造函數,類似於Dictionary<T>
。 在那種情況下,我需要做...
private IEqualityComparer<T> _comparer;
public MyClass() {}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if((_comparer != null && _comparer.Equals(o1, o2)) || (o1.Equals(o2)))
{
...
}
}
要刪除這個冗長的 if 語句,如果使用常規構造函數,我可以將_comparer
默認設置為“默認比較器”。 我搜索了typeof(T).GetDefaultComparer()
類的東西,但找不到類似的東西。
我確實找到了EqualityComparer<T>.Default
,我可以使用它嗎? 然后這個片段......
public MyClass()
{
_comparer = EqualityComparer<T>.Default;
}
void DoSomething(T o1, T o2)
{
if(_comparer.Equals(o1, o2))
{
...
}
}
...為所有可能的情況提供與使用o1.Equals(o2)
相同的結果?
(作為旁注,這是否意味着我還需要對<T>
使用任何特殊的通用約束?)
它應該是相同的,但不能保證,因為它取決於類型T
的實現細節。
解釋:
如果沒有對T
的約束, o1.Equals(o2) 將調用Object.Equals
,即使T
實現IEquatable<T>
。
EqualityComparer<T>.Default
但是,如果T
沒有實現IEquatable<T>
,則僅使用Object.Equals
。 如果它確實實現了該接口,它使用IEquatable<T>.Equals
。
只要T
的實現Object.Equals
只是調用IEquatable<T>.Equals
結果是一樣的。 但在下面的例子中,結果是不一樣的:
public class MyObject : IEquatable<MyObject>
{
public int ID {get;set;}
public string Name {get;set;}
public override bool Equals(object o)
{
var other = o as MyObject;
return other == null ? false : other.ID == ID;
}
public bool Equals(MyObject o)
{
return o.Name == Name;
}
}
現在,像這樣實現 class 沒有任何意義。 但是,如果MyObject
的實現者只是忘記覆蓋Object.Equals
,您將遇到同樣的問題。
結論:
使用EqualityComparer<T>.Default
是 go 的好方法,因為您不需要支持有缺陷的對象!
默認情況下,除非在 class、 Object.Equals(a,b)
/ a.Equals(b)
中被覆蓋,否則按引用執行比較。
EqualityComparer<T>.Default
將返回什么比較器取決於T
。 例如,如果T: IEquatable<>
則將創建相應的EqualityComparer<T>
。
您可以使用 null coaelescense 運算符? 縮短 if 如果它真的很重要
if ((_comparer ?? EqualityComparer<T>.Default).Equals(o1, o2))
{
}
如果您在構造 object 時未指定比較器,這正是Dictionary<>
和 BCL 中的其他通用 collections 所做的。 這樣做的好處是EqualityComparer<T>.Default
將為IEquatable<T>
類型、可為空的類型和枚舉返回正確的比較器。 如果 T 不是這些,它將像您的舊代碼一樣進行簡單的 Equals 比較。
是的,我認為使用EqualityComparer<T>.Default
是明智的,因為如果類型T
實現它,它使用IEquatable<T>
的實現,否則使用Object.Equals
的覆蓋。 你可以這樣做:
private IEqualityComparer<T> _comparer;
public IEqualityComparer<T> Comparer
{
get { return _comparer?? EqualityComparer<T>.Default;}
set { _comparer=value;}
}
public MyClass(IEqualityComparer<T> comparer)
{
_comparer = comparer;
}
void DoSomething(T o1, T o2)
{
if(Comparer.Equals(o1, o2))
{
...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.