簡體   English   中英

平等比較器<t> .Default vs. T.Equals</t>

[英]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.

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