如何使用对象的标识作为Dictionary 的键
是否可以使用一个对象作为Dictonary
的关键字,使得Dictionary只有在相同的情况下才将对象视为相等?
例如,在下面的代码中,我希望第2行返回11而不是12:
Dictionary dict = new Dictionary(); object a = new Uri("http://www.google.com"); object b = new Uri("http://www.google.com"); dict[a] = 11; dict[b] = 12; Console.WriteLine(a == b); // Line 1. Returns False, because a and b are different objects. Console.WriteLine(dict[a]); // Line 2. Returns 12 Console.WriteLine(dict[b]); // Line 3. Returns 12
当前的Dictionary实现在键上使用object.GetHashCode()
和object.GetHashCode()
; 但我正在寻找一种不同类型的字典,它使用对象的身份作为关键字(而不是对象的值)。 在.NET中是否有这样的字典或者我是否必须从头开始实现它?
您不需要构建自己的字典 – 您需要构建自己的IEqualityComparer
实现,它使用哈希和相等的标识。 我不认为框架中存在这样的东西,但由于RuntimeHelpers.GetHashCode
,它很容易构建。
public sealed class IdentityEqualityComparer : IEqualityComparer where T : class { public int GetHashCode(T value) { return RuntimeHelpers.GetHashCode(value); } public bool Equals(T left, T right) { return left == right; // Reference identity comparison } }
我已经将T
限制为引用类型,这样你最终会得到字典中的对象 ; 如果你将它用于值类型,你可能会得到一些奇怪的结果。 (我不知道它会如何起作用;我怀疑它不会。)
有了这个,其余的很容易。 例如:
Dictionary identityDictionary = new Dictionary(new IdentityEqualityComparer());
当然其他答案完全正确,但我编写了自己的版本以满足我的需求:
/// /// An equality comparer that compares objects for reference equality. /// /// The type of objects to compare. public sealed class ReferenceEqualityComparer : IEqualityComparer where T : class { #region Predefined private static readonly ReferenceEqualityComparer instance = new ReferenceEqualityComparer (); /// /// Gets the default instance of the /// class. /// /// A instance. public static ReferenceEqualityComparer Instance { get { return instance; } } #endregion /// public bool Equals(T left, T right) { return Object.ReferenceEquals(left, right); } /// public int GetHashCode(T value) { return RuntimeHelpers.GetHashCode(value); } }
设计理由:
- 课程是
sealed
。
如果课程不是为了扩展而设计的,我将通过密封来避免所有费用。
– Eric Lippert我知道许多人(包括我自己)认为class级确实应该默认密封。
– Jon Skeet - 有一个
Instance
静态只读属性来公开此类的单个实例。 - 它使用
Object.ReferenceEquals()
而不是==
因为ReferenceEquals
更明确。 - 它使用
RuntimeHelpers.GetHashCode()
因为我不想使用对象的可能重写的GetHashCode
,这可能与ReferenceEquals
的行为不匹配。 这也避免了空检查。 - 它有文件。
使用您自己的相等比较器
public class ObjectIdentityEqualityComparer : IEqualityComparer
请注意,可以覆盖GetHashCode
,但使用Equals
进行关键检查。
使用带有IEqualityComparer
comparer的Dictionary