簡體   English   中英

Dictionary.ContainsKey返回False,但想要True

[英]Dictionary.ContainsKey return False, but a want True

namespace Dic
{
public class Key
{
    string name;
    public Key(string n) { name = n; }
}

class Program
{
    static string Test()
    {
        Key a = new Key("A");
        Key b = new Key("A");
        System.Collections.Generic.Dictionary<Key, int> d = new System.Collections.Generic.Dictionary<Key, int>();
        d.Add(a, 1);
        return d.ContainsKey(b).ToString();
    }

    static void Main(string[] args)
    {
        System.Console.WriteLine(Test());
    }
}
}

我應該改變什么才能成真?

你想要真實 - 但a和b是不同的對象。

您需要在類Key上覆蓋GetHashCode和Equals

public class Key
{
    string name;
    public Key(string n) { name = n; }

    public override int GetHashCode()
    {
        if (name == null) return 0;
        return name.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        Key other = obj as key;
        return other != null && other.name == this.name;
    }
}

如果你重寫Key.GetHashCode和Key.Equals,它可能會有所幫助。

Key

public override bool Equals(object obj)
{
    var k = obj as Key;
    if (k != null)
    {
        return this.name == k.name;
    }
    return base.Equals(obj);
}

public override int GetHashCode()
{
    return this.name.GetHashCode();
}

如果你沒有能夠像其他人提到的那樣覆蓋相等的運算符/ Equals / GetHashCode(如你所知,你不控制對象的源代碼),你可以在字典的構造函數中提供IEqualityComparer<Key>實現執行你的平等檢查。

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

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

就目前而言,您的Key是一個引用對象,因此除非您告訴世界(或字典),否則僅在引用時確定相等性。

覆蓋類的GetHashCode和Equals方法以使其在字典中正常工作並不是一個非常好的方法。 字典的行為方式應該是字典的實現細節,而不是用作鍵的任何類。 當你想在具有不同行為的不同詞典中使用該類時,你會遇到麻煩。 或者,如果您無權訪問類源代碼。

一個更好的鼠標陷阱是給字典自己的比較器。 例如:

using System;
using System.Collections.Generic;

class Program {
    static void Main(string[] args) {
        var d = new Dictionary<Key, int>(new MyComparer());
        d.Add(new Key("A"), 1);
        Console.WriteLine(d.ContainsKey(new Key("a")));
        Console.ReadLine();
    }
    private class MyComparer : IEqualityComparer<Key> {
        public bool Equals(Key x, Key y) {
            return string.Compare(x.Name, y.Name, true) == 0;
        }
        public int GetHashCode(Key obj) {
            return obj.Name.ToUpper().GetHashCode();
        }
    }
    public class Key {
        public string Name { get; set; }
        public Key(string name) { Name = name; }
    }
}

要將您自己的類用作字典鍵,您應該重寫GetHashCode和Equals。 否則,它將使用內存地址來檢查是否相等。

public class Key
    {
        string name;
        public Key(string n) { name = n; }

        public override int GetHashCode()
        {
            return name.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var other = obj as Key;
            if( other == null )
                return false;

            return name == other.name;
        }
    }

你的問題是

new Key("A").Equals(new Key("A"))==false.

new Key("A").GetHashCode()!=new Key("A").GetHashCode()

解決這個問題,我覺得應該可行。 要修復它,請覆蓋Equals方法並檢查名稱值是否相同。 如果要覆蓋Equals,還應覆蓋GetHashCode。

您需要覆蓋Key類的Equals和GetHashCode方法。

它們內部具有相同的值但是!= b,因為它們是2個不同的變量。

您需要覆蓋Key類的EqualsGetHashCode方法。 在您的情況下,您可以根據鍵的名稱進行比較(如果您的類更復雜,則可以在任何其他唯一屬性上進行比較)。

public class Key {
    string name;
    public Key(string n) { name = n; }

    public override bool Equals(object obj) {
        Key k = obj as Key;
        if (k == null)
            return false;
        return name.Equals(k.name);
    }

    public override int GetHashCode() {
        return name.GetHashCode();
    }
}

1.覆蓋等於,獲取哈希代碼和'=='運算符。

Key類必須重寫Equals ,以便Dictionary檢測它們是否相同。 默認實現僅檢查引用。

這里:

        public bool Equals(Key other)
        {
            return this == other;
        }

        public override bool Equals(object obj)
        {
            if (obj == null || !(obj is Key))
            {
                return false;
            }

            return this.Equals((Key)obj);
        }

        public static bool operator ==(Key k1, Key k2)
        {
            if (object.ReferenceEquals(k1, k2))
            {
                return true;
            }

            if ((object)k1 == null || (object)k2 == null)
            {
                return false;
            }

            return k1.name == k2.name;
        }

        public static bool operator !=(Key k1, Key k2)
        {
            if (object.ReferenceEquals(k1, k2))
            {
                return false;
            }

            if ((object)k1 == null || (object)k2 == null)
            {
                return true;
            }

            return k1.name != k2.name;
        }

        public override int GetHashCode()
        {
            return this.name == null ? 0 : this.name.GetHashCode();
        }

2.如果可能,請使用結構。

您應該使用這樣的不可變數據類型的結構,因為它們是按值傳遞的。 這意味着你不會意外地將兩個不同的值混合到同一個鍵中。

然后,您需要在Key類上重寫GetHashCode和Equals。

如果不這樣做,您將獲得兩者的默認實現。 這導致a和b的哈希碼很可能不一樣(我不知道默認實現是怎么樣的),而a肯定不等於b(默認的Equals()實現檢查引用相等)。

在您的情況下,假設“name”不是null,它可以實現為

   public class Key
   {
        string name;
        public override int GetHashCode()
        {
             return name.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
              return false;
            }

            Key objAsKey = obj as Key;
            if (objAsKey == null)
            {
              return false;
            }

            return this.name.Equals(objAsKey.Name);
        }
    }

這是否是一個令人滿意的哈希是一個不同的故事,但它顯示了原則。

在這種情況下,ContainsKey將Key作為對象進行比較,並檢查對象本身是否相同 - 它們不是。 你需要實現IComparable或覆蓋Key.Equals或類似的東西,以使它做你想要的。

暫無
暫無

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

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