在hashset <myclass>的字典中包含Key

时间:2016-04-30 00:38:19

标签: c# dictionary hashset containskey

我有一本字典:

Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...

我有:

HashSet<myClass> myHashSet = ...

我想检查字典(myDict)是否包含myHashSet。

我试图覆盖两种方法:

1)相等

2)GetHashCode

public class myClass
{
    public string id;
    public int number;

    public override bool Equals(object obj)
    {
        myClass other = obj as myClass;
        bool ret = false;
        if (other != null)
        {
            ret = (this.number == other.number) && (this.id == other.id);
        }
        return ret;
    }

    public override int GetHashCode()
    {
        return this.number ^ this.id.GetHashCode();
    }
};

不幸的是,在字典中找到的键,代码返回false: myDict.ContainsKey(myHashSet)

任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:2)

仅仅因为你覆盖了myClass Equals(GetHashCode()并不意味着你覆盖HashSet<myClass> Equals(GetHashCode(),这是你进行字典查找时使用的内容。

如果你想让它工作,你需要将IEqualityComparer<HashSet<myClass>>传递给字典的构造函数,以便在进行字典查找时使用该比较器。

public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
    public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (ReferenceEquals(null, x)) return false;
        if (ReferenceEquals(null, y)) return false;
        return x.SetEquals(y);
    }

    public int GetHashCode(HashSet<myClass> obj)
    {
        unchecked
        {
            int x = 0;
            foreach (var myClass in obj)
            {
                x = (x*397) ^ myClass?.GetHashCode() ?? 0;
            }
            return x;
        }
    }
}

//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());

非常重要的注意事项:如果您执行任何导致Equals(GetHashCode()作为查找键放入后更改的内容,则字典键(和哈希集)会发生严重破坏。如果在将HashSet<myClass>或其中一个myClass对象放入字典后修改它,则会破坏字典并可能破坏HashSet。请参阅Eric Lippert撰写的this very good blog post&#34; GetHashCode指南和规则&#34;

答案 1 :(得分:1)

覆盖GetHasCode和Equal是在比较myClass的实例时。

以下是使用ContainsKey的示例,它通过对象引用进行检查。

Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
            var myHashSet = new HashSet<string>();

            hashSetDictionary.Add(myHashSet, null);
            Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));

以下是对您的代码的更新

 public class myClass
    {
        public myClass(string text, int num)
        {
            this.Text = text;
            this.Num = num;
        }

        public string Text { get; set; }
        public int Num { get; set; }
    }

    public class MyObj { }

    public class AlwaysTrueHashSet<T> : HashSet<T>
    {
        public override bool Equals(object obj)
        {
            return this.GetHashCode() == obj.GetHashCode();
        }

        public override int GetHashCode()
        {
            return "Counting hashcode".GetHashCode();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {


            Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,


            List<MyObj>>();
            var myHashSet1 = new AlwaysTrueHashSet<myClass>();
            myHashSet1.Add(new myClass("123", 5));
            myDict.Add(myHashSet1, null);



            var myHashSet2 = new AlwaysTrueHashSet<myClass>();
            myHashSet2.Add(new myClass("123", 5));

            /*
             * when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
             * That's the default behavior.
             * 
             * extend HashSet, and override the gethashcode and equal methods  
             */
            if (myDict.ContainsKey(myHashSet2))
            {
                Console.WriteLine("in");
                int i = 3; // it doesn't get this line }  
            }
        }
    }