0

IDictionary<KeyClass, ValueClass>在我的一个项目中使用。KeyClass非常简单,只包含两个整数。

public class KeyClass
{
    public int ValueA{get;set;}
    public int ValueB{get;set;}
}

我正在从字典中访问值,如下所示:

var k = new KeyClass(1, 1);
var v = myDictionary[k];

字典肯定包含KeyClass带有ValueA = 1和类似的ValueB = 1许多其他键的键。但我有例外:

The given key is not present in the dictionary.

IComparable在课堂上实施,KeyClass但没有解决我的问题。我用谷歌搜索并找到了这篇CodeProject文章。它描述了使用类实现IEqualityComparer<T>接口的以下技术。我在课堂上定义了它:

public class KeyClass
{
    public int ValueA{get;set;}
    public int ValueB{get;set;}

    public class EqualityComparer : IEqualityComparer<KeyClass>
    {
        public bool Equals(KeyClass a, KeyClass b)
        {
            return a.ValueA == b.ValueA && a.ValueB == b.ValueB;
        }

        public int GetHashCode(KeyClass k)
        {
            return k.ValueA ^ k.ValueB;
        }
    }
}

现在我必须声明IDictionary<KeyClass, ValueClass>如下:

var d = new Dictionary<KeyClass, ValueClass>(new KeyClass.EqualityComparer());

之后事情进展顺利。

我的问题是我在保存环境(.Net 4.0,Windows 7 桌面应用程序)中使用相同的类并且在另一个项目中KeyClass没有IEqualityComparet<T>实现,但是为什么在我将类放入这个项目后它停止工作?

4

2 回答 2

1

没有理由实施IEqualityComparer<KeyClass>. 而是重写. GetHashCode_EqualsKeyClass

public class KeyClass
{
    public int ValueA{get;set;}
    public int ValueB{get;set;}

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        KeyClass p = obj as KeyClass;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return a.ValueA == b.ValueA && a.ValueB == b.ValueB;
    }

    public bool Equals(KeyClass p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return this.ValueA == p.ValueA && this.ValueB == b.ValueB;
    }

    public int GetHashCode(KeyClass k)
    {
        return k.ValueA ^ k.ValueB;
    }
}

只有在进行自定义比较时才需要IEqualityComparer<KeyClass>- 与默认比较不同的东西。但是既然你控制KeyClass了,就可以在类中指定默认比较。

如果您这样做,那么您不必在创建字典时提供比较器。也就是说,你可以写:

var d = new Dictionary<KeyClass, ValueClass>();

请参阅 Equals() 和 Operator == 指南

它之前不起作用的原因可能是因为引用类型的默认比较是引用相等。所以如果你写:

var k = new KeyClass(1, 1);
var v = new ValueClass(..);
d.Add(k, v);

var k1 = new KeyClass(1, 1);
var v1 = d[k1];

你会得到“key not found”,因为 'k' 和 'k1' 不是同一个对象。但如果你写:

var v1 = d[k];

您会找到该值,因为k它是您存储在字典中的键。

覆盖Equals解决了这个问题。

于 2012-04-22T00:10:41.360 回答
0

类是一种引用类型——默认情况下,一个引用与另一个引用的比较是基于它们是否指向类的同一实例,而不是基于其属性的值。

您可以使用添加项目的原始实例从字典中检索项目,但不能使用恰好具有相同 ValueA 和 ValueB 值的其他实例。

如果您想要这种行为,您必须使用值类型(结构而不是类)、自定义比较器(如您所做的那样),或者您必须覆盖 KeyClass 的 Equals() 和 GetHashCode() 方法。

在这种情况下,使用结构可能是最好的选择,但了解使用它们的含义很重要,您可以在此处阅读: 结构(C# 编程指南)

于 2012-04-21T23:15:59.360 回答