如何使用对象的标识作为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 { public int GetHashCode(object o) { return o.GetHashCode(); } public bool Equals(object o1, object o2) { return object.ReferenceEquals(o1, o2); } } 

请注意,可以覆盖GetHashCode ,但使用Equals进行关键检查。

使用带有IEqualityComparer comparer的Dictionary