字典中的引用类型

Dim*_*zyr 0 c# dictionary

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

using System.Collections.Generic;
...
Dictionary<T1, T2> myDict = new Dictionary<T1, T2>();
Run Code Online (Sandbox Code Playgroud)

据我了解,第一种类型 - 是关键。并且比intstring类型更常见。

Erg*_*wun 5

可以使用引用类型作为字典中的键。如果你这样做,要记住的重要一点是,引用类型默认使用引用相等。

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

问题:

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

class Foo
{
    public int X { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

因此,如果您创建两个实例并持有相同的值,则它们不会被视为相等:

var a = new Foo { X = 1 };
var b = new Foo { X = 1 };
Console.WriteLine(a == b); // false
Console.WriteLine(a.Equals(b)); // false
Run Code Online (Sandbox Code Playgroud)

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

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

解决方案

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

选项 I:实现价值平等:

因此,如果您确实想为您的引用类型实现值相等,则应遵循以下准则,这将为您提供类似的信息(不要忘记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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在Foo2表示相同值的两个实例被认为是相等的:

var c = new Foo2 { X = 1 };
var d = new Foo2 { X = 1 };
Console.WriteLine(c == d); // true
Console.WriteLine(c.Equals(d)); // true
Run Code Online (Sandbox Code Playgroud)

如果您使用c作为键值存储在字典中,您能够使用d以下方法检索它:

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

选项 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

a并且b仍然被认为是不相等的,但是现在您可以使用 将值存储在字典中a,并使用 检索它b

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