簡體   English   中英

使用IEqualityComparer和Equals / GethashCode Override有什么區別?

[英]What is the difference between using IEqualityComparer and Equals/GethashCode Override?

當我使用字典有時我必須更改默認的等於意思,以便比較鍵。 我看到如果我在鍵的類上重寫Equals和GetHashCode,或者我創建了一個實現IEqualityComparer的新類,我有相同的結果。 那么使用IEqualityComparer和Equals / GethashCode Override有什么區別? 兩個例子:

class Customer
{
    public string name;
    public int age;
    public Customer(string n, int a)
    {
        this.age = a;
        this.name = n;
    }
    public override bool Equals(object obj)
    {
        Customer c = (Customer)obj;
        return this.name == c.name && this.age == c.age;
    }
    public override int GetHashCode()
    {
        return (this.name + ";" + this.age).GetHashCode();
    }
}
  class Program
{
    static void Main(string[] args)
    {
        Customer c1 = new Customer("MArk", 21);
        Customer c2 = new Customer("MArk", 21);
        Dictionary<Customer, string> d = new Dictionary<Customer, string>();
        Console.WriteLine(c1.Equals(c2));
        try
        {
            d.Add(c1, "Joe");
            d.Add(c2, "hil");
            foreach (KeyValuePair<Customer, string> k in d)
            {
                Console.WriteLine(k.Key.name + " ; " + k.Value);
            }
        }
        catch (ArgumentException)
        {
            Console.WriteLine("Chiave già inserita in precedenza");
        }
        finally
        {
            Console.ReadLine();
        }
    }
}

}

第二個 :

class Customer
{
    public string name;
    public int age;
    public Customer(string n, int a)
    {
        this.age = a;
        this.name = n;
    }
}
class DicEqualityComparer : EqualityComparer<Customer>
{
    public override bool Equals(Customer x, Customer y) // equals dell'equalitycomparer
    {
        return x.name == y.name && x.age == y.age;
    }
    public override int GetHashCode(Customer obj)
    {
        return (obj.name + ";" + obj.age).GetHashCode();
    }
}
class Program
{
    static void Main(string[] args)
    {
        Customer c1 = new Customer("MArk", 21);
        Customer c2 = new Customer("MArk", 21);
        DicEqualityComparer dic = new DicEqualityComparer();
        Dictionary<Customer, string> d = new Dictionary<Customer, string>(dic);
        Console.WriteLine(c1.Equals(c2));
        try
        {
            d.Add(c1, "Joe");
            d.Add(c2, "hil");
            foreach (KeyValuePair<Customer, string> k in d)
            {
                Console.WriteLine(k.Key.name + " ; " + k.Value);
            }
        }
        catch (ArgumentException)
        {
            Console.WriteLine("Chiave già inserita in precedenza");
        }
        finally
        {
            Console.ReadLine();
        }
    }
}

}

兩個例子都有相同的結果。

提前致謝。

當您重寫EqualsGetHashCode您正在更改對象確定它是否等於另一個的方式。 還有一個注意事項,如果使用==運算符比較對象,它將不會具有與Equals相同的行為,除非您也覆蓋運算符。

這樣做就改變了單個類的行為,如果你需要為其他類提供相同的邏輯呢? 如果您需要“通用比較”。 這就是為什么你有IEqualityComparer

看看這個例子:

interface ICustom
{
    int Key { get; set; }
}
class Custom : ICustom
{
    public int Key { get; set; }
    public int Value { get; set; }
}
class Another : ICustom
{
    public int Key { get; set; }
}

class DicEqualityComparer : IEqualityComparer<ICustom>
{
    public bool Equals(ICustom x, ICustom y)
    {
        return x.Key == y.Key;
    }

    public int GetHashCode(ICustom obj)
    {
        return obj.Key;
    }
}

我有兩個不同的類,都可以使用相同的比較器。

var a = new Custom { Key = 1, Value = 2 };
var b = new Custom { Key = 1, Value = 2 };
var c = new Custom { Key = 2, Value = 2 };
var another = new Another { Key = 2 };

var d = new Dictionary<ICustom, string>(new DicEqualityComparer());

d.Add(a, "X");
// d.Add(b, "X"); // same key exception
d.Add(c, "X");
// d.Add(another, "X"); // same key exception

請注意,我沒有在兩個類中都不重寫EqualsGetHashCode 我可以在任何實現ICustom對象中使用這個比較器,而不必重寫比較邏輯。 我還可以為“父類”創建IEqualityComparer ,並在繼承的類上使用。 我可以讓比較器以不同的方式運行,我可以讓一個比較Value而不是Key

因此IEqualityComparer允許更大的靈活性,您可以實現通用解決方案。

對象的Equals() GetHashCode()實現了對象固有的相等概念。 但是,您可能希望使用等同的替代概念 - 例如,僅使用ZIP代碼而不是完整地址的地址對象的相等比較器。

對於這個目的,它基本上是相同的,只有一個微妙的區別。 在第一個示例中,您使用Object類型的參數覆蓋Equals,然后必須將其強制轉換為Customer,但是,在第二個示例中,您可以使用Customer類型的參數,這意味着無需強制轉換。

這意味着重寫Equals允許在不同類型的兩個對象之間進行比較(在某些情況下可能需要),但是,實現IEqualityComparer不會給予這種自由(在某些情況下也可能需要)。

在許多情況下,人們可能希望使用除100%等效之外的其他內容來使用Dictionary定位對象。 作為一個簡單的例子,人們可能希望有一個以不區分大小寫的方式匹配的字典。 實現這一目標的一種方法是在將字符串存儲到字典或執行查找之前將字符串轉換為規范的大寫形式。 另一種方法是為字典提供IEqualityComparer<string> ,它將計算哈希碼並在某種與案例無關的函數中檢查相等性。 在某些情況下,將字符串轉換為規范形式並盡可能使用該形式將更有效,但在其他情況下,僅將字符串存儲為其原始形式更有效。 我希望.NET提供的一個功能可以提高這些詞典的實用性,這將是一種請求與給定鍵相關聯的實際鍵對象的方法(因此,如果字典包含字符串"WowZo"作為鍵,則可以查找"wowzo"並得到"WowZo" ;遺憾的是,如果TValue不包含冗余引用,則檢索實際密鑰對象的唯一方法是枚舉整個集合。

另一種情況是,使用替代的比較方法可能有用的是,當一個對象持有對一個可變類型的實例的引用時,但是永遠不會將該實例暴露給任何可能使其變異的實例。 通常,具有相同值序列的int[]兩個實例將不可互換,因為將來可能會將它們中的一個或兩個更改為包含不同的值。 另一方面,如果將使用字典來保存和查找int[]值,則每個字段將是Universe中任何位於int[]實例的唯一引用,並且如果沒有任何實例將被修改並且暴露於外部代碼,將相同的數組視為具有相同的值序列可能是有用的。 由於Array.Equals測試嚴格等價(引用相等),因此有必要使用其他一些方法來測試數組的等價性。

暫無
暫無

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

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