c# - 使用自定义对象作为字典键

标签 c#

我想使用自定义对象作为字典键,主要是,我有这样的东西:(我不能使用 .net 4.0,所以我没有元组)

class Tuple<A, B> : IEquatable<Tuple<A,B>>
{
  public A AValue { get; set; }
  public B BValue { get; set; }

  public Tuple(A a, B b){ AValue = a; BValue = b; }

  public bool Equals(Tuple<A, B> tuple)
  {
    return tuple.AValue.Equals(AValue) && tuple.BValue.Equals(BValue);
  }

  public bool Equals(object o)
  {
  return this.Equals(o as Tuple<A,B>);
  }
}

然后我会做这样的事情。

  var boolmap = new Dictionary<Tuple<bool, bool>, string>();
  boolmap.Add(new Tuple<bool,bool>(true, true), "A");
  boolmap.Add(new Tuple<bool,bool>(true, false), "B");
  boolmap.Add(new Tuple<bool,bool>(false, true), "C");
  boolmap.Add(new Tuple<bool,bool>(false, false), "D");
  var str = boolmap[new Tuple<bool,bool>(true, false)];

我在最后一行收到 KeyNotFound 异常。为什么是这样 ?我实现 IEquatable 还不够吗?

谢谢

最佳答案

您还需要覆盖 GetHashCode() (最好还有 Equals() )。您的 otherwise-equal 对象返回不同的哈希码,这意味着在查找时找不到 key 。

GetHashCode()契约(Contract)指定当两个对象被认为相等时,两个对象的返回值必须相等。这是你问题的根源;你的类(class)不符合这个要求。契约(Contract)没有规定如果它们不相等则该值必须不同,但这将提高性能。 (如果所有对象都返回相同的哈希码,从性能的角度来看,您也可以使用平面列表。)

在您的案例中,一个简单的实现可能是:

public override int GetHashCode()
{
    return AValue.GetHashCode() ^ BValue.GetHashCode();
}

请注意,测试是否 AValue 可能是个好主意或 BValuenull . (这会有些复杂,因为您不限制泛型类型 AB ,所以您不能只将值与 null 进行比较——例如,类型可以是值类型。) 1

让您打算用作字典键的类不可变也是一个好主意。如果更改用作键的对象的值,字典将表现出奇怪的行为,因为该对象现在位于它不属于的存储桶中。


1 请注意,您可以使用 EqualityComparer<A>.Default.GetHashCode(AValue) (和 BValue 类似)在这里,因为这将消除对 null 检查的需要。

关于c# - 使用自定义对象作为字典键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6999191/

相关文章:

c# - Long to Object 隐式转换中断了吗?

c# - 如何在 C# 中过滤和组合 2 个数据集

c# - 是否有任何扩展或方法可以像在 VS 中一样在 VS Code 中添加 C# 类?

c# - 使用 Forms 身份验证首次登录 ASP.NET MVC 后强制用户更改密码

c# - asp.net 上的 CSS 样式的 DropDownList

c# - 为什么如果该行抛出异常,则执行后增量操作?

c# - 模拟内部对象的事件不会触发?

c# - 如何枚举传递的方法参数

c# - POST 上 PartialViews 的绑定(bind)模型

c# - 我的 Raycast 似乎没有任何范围 - 仅检测放置在发射游戏对象旁边的对象