可以将字典中的第一种类型设为引用类型吗?如果是,那是什么意思?
using System.Collections.Generic;
...
Dictionary<T1, T2> myDict = new Dictionary<T1, T2>();
Run Code Online (Sandbox Code Playgroud)
据我了解,第一种类型 - 是关键。并且比int或string类型更常见。
可以使用引用类型作为字典中的键。如果你这样做,要记住的重要一点是,引用类型默认使用引用相等。
如果您希望键类型的多个实例表示相同的值,则需要确保您的引用类型使用值相等。例如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)