C# 泛型字典 TryGetValue 找不到键



我有一个简单的例子:

using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<MyKey, string> data = new Dictionary<MyKey, string>();
            data.Add(new MyKey("1", "A"), "value 1A");
            data.Add(new MyKey("2", "A"), "value 2A");
            data.Add(new MyKey("1", "Z"), "value 1Z");
            data.Add(new MyKey("3", "A"), "value 3A");
            string myValue;
            if (data.TryGetValue(new MyKey("1", "A"), out myValue))
                Console.WriteLine("I have found it: {0}", myValue );
        }
    }
    public struct MyKey
    {
        private string row;
        private string col;
        public string Row { get { return row; } set { row = value; } }
        public string Column { get { return col; } set { col = value; } }
        public MyKey(string r, string c)
        {
            row = r;
            col = c;
        }
    }
}

这很好用。但是,如果我以这种方式通过MyKey类更改MyKey结构:

public class MyKey

则方法TryGetValue没有找到任何密钥,尽管密钥在那里。

我确信我错过了一些显而易见的东西,但我不知道是什么。

知道吗?

感谢


**解决方案**

(请参阅公认的解决方案以获得更好的GetHashCode分辨率)

我像这样重新定义了MyKey类,现在一切都很好:

public class MyKey
{
    private string row;
    private string col;
    public string Row { get { return row; } set { row = value; } }
    public string Column { get { return col; } set { col = value; } }
    public MyKey(string r, string c)
    {
        row = r;
        col = c;
    }
    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is MyKey)) return false;
        return ((MyKey)obj).Row == this.Row && ((MyKey)obj).Column == this.Column;
    }
    public override int GetHashCode()
    {            
        return (this.Row + this.Column).GetHashCode();
    }    
}

感谢所有回答这个问题的人。

您需要覆盖类MyKey 中的Equals()GetHashCode()

也许是这样的:

GetHashCode()

public override int GetHashCode()
{
   return GetHashCodeInternal(Row.GetHashCode(),Column.GetHashCode());
}
//this function should be move so you can reuse it
private static int GetHashCodeInternal(int key1, int key2)
{
    unchecked
    {
        //Seed
        var num = 0x7e53a269;
        //Key 1
        num = (-1521134295 * num) + key1;
        num += (num << 10);
        num ^= (num >> 6);
        //Key 2
        num = ((-1521134295 * num) + key2);
        num += (num << 10);
        num ^= (num >> 6);
        return num;
    }
}

等于

public override bool Equals(object obj)
{
    if (obj == null)
        return false;
    MyKey p = obj as MyKey;
    if (p == null)
        return false;
    // Return true if the fields match:
    return (Row == p.Row) && (Column == p.Column);
}

因为类在默认情况下使用引用比较进行比较。

如果你比较两个对象,你就是在做一个对象。ReferenceEquals(obj1,obj2)

如果比较两个structs,则进行值比较(例如比较两个int)。

如果你想比较两个MyKey对象,你需要实现你自己的EqualsGetHashCode方法,它将被字典自动使用。

Struct是值类型,class是引用类型,所以当您使用Struct时,会比较它内部的所有值,但当您使用class时,只检查对象引用。

您可以通过重写Equals()方法来更改某些类的行为。如果需要,也可以覆盖==运算符。请参阅Overloading Equals()和Operator==(C#编程指南)指南中的示例。

编辑:

你的Equals()方法应该是这样的:

public override bool Equals(System.Object obj)
    {
        MyKey p = obj as MyKey;
        if ((System.Object)p == null)
        {
            return false;
        }
        // Return true if the fields match:
        return (row == p.row) && (col == p.col);
    }

最新更新