字典中的引用类型

时间:2014-03-01 00:59:25

标签: c# dictionary

可以将字典中的第一个类型作为引用类型吗? 如果有,那是什么意思呢?

using System.Collections.Generic;
...
Dictionary<T1, T2> myDict = new Dictionary<T1, T2>();

据我了解,第一种类型 - 是关键。而且比 int string 类型更频繁。

2 个答案:

答案 0 :(得分:4)

可以使用引用类型作为字典中的键。要记住的重要一点是,引用类型使用引用相等作为默认值。

如果希望密钥类型的多个实例表示相同的值,则需要确保引用类型使用值相等。例如,string是一种已经支持值相等的引用类型,因此使用字符串作为密钥是安全且容易的。

问题:

以下引用类型未实现值相等:

class Foo
{
    public int X { get; set; }
}

因此,如果您创建两个实例,保持相同的值,则认为它们不相等:

var a = new Foo { X = 1 };
var b = new Foo { X = 1 };
Console.WriteLine(a == b); // false
Console.WriteLine(a.Equals(b)); // false

如果您使用a作为键将值存储在字典中,则无法使用b检索它:

var dict = new Dictionary<Foo, int>();
dict[a] = 10;
Console.WriteLine(dict[b]); // Key not found exception

<强>解决方案

要解决此问题,您可以(I)为您的类型实现值相等,或者(II)覆盖字典比较键的方式:

选项I:实现价值平等:

因此,如果您确实希望为引用类型实现值相等,那么您应该遵循these guidelines,这将为您提供类似的内容(不要忘记GetHashCode):

class Foo2 : IEquatable<Foo2>
{
    public int X { get; set; }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as Foo2);
    }

    public bool Equals(Foo2 other)
    {
        if (Object.ReferenceEquals(other, null))
        {
            return false;
        }

        // Optimization for a common success case. 
        if (Object.ReferenceEquals(this, other))
        {
            return true;
        }

        if (this.GetType() != other.GetType())
            return false;

        return (X == other.X);
    }

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

    public static bool operator ==(Foo2 lhs, Foo2 rhs)
    {
        if (Object.ReferenceEquals(lhs, null))
        {
            if (Object.ReferenceEquals(rhs, null))
            {
                return true;
            }

            return false;
        }

        return lhs.Equals(rhs);
    }

    public static bool operator !=(Foo2 lhs, Foo2 rhs)
    {
        return !(lhs == rhs);
    }
}

现在,两个代表相同值的Foo2实例被视为相等:

var c = new Foo2 { X = 1 };
var d = new Foo2 { X = 1 };
Console.WriteLine(c == d); // true
Console.WriteLine(c.Equals(d)); // true

如果您使用c作为键将值存储在词典中, 将能够使用d检索它:

var dict = new Dictionary<Foo2, int>();
dict[c] = 10;
Console.WriteLine(dict[d]); // 10

选项II:使用自定义相等比较器:

如果您不打算通常比较Foo的实例,但仍希望能够在字典中比较它们时使用值相等,则可以提供自定义相等比较器作为实现完整值的替代方法平等:

class FooComparer : IEqualityComparer<Foo>
{

    public bool Equals(Foo x, Foo y)
    {
        // Doesn't handle null arguments!
        return x.X == y.X;
    }

    public int GetHashCode(Foo obj)
    {
        return obj.X;
    }
}

ab仍被视为不相等,但现在您可以使用a在字典中存储值,并使用b检索它:

var dict = new Dictionary<Foo, int>(new FooComparer());
dict[a] = 10;
Console.WriteLine(dict[b]); // 10

答案 1 :(得分:2)

.NET框架中的每个对象都有GetHashCodeEquals方法。这些都是在字典中用作密钥所需要的。

默认引用类型使用引用相等性(即内存中相同对象的键),但您可以覆盖GetHashCodeEquals以提供您喜欢的任何相等语义。