【问题标题】:Cannot Find Key in Generic Dictionary [duplicate]在通用字典中找不到键[重复]
【发布时间】:2010-03-05 18:44:29
【问题描述】:

我无法按键找到字典条目。我有一个如下界面:

public interface IFieldLookup
{
    string FileName { get; set; }
    string FieldName { get; set; }
}

然后我有一本像这样的字典:

Dictionary<IFieldLookup, IField> fd

当我尝试通过键从字典中检索元素时,我得到了 KeyNotFoundException。我假设我必须实施某种类型的比较 - 如果我的假设是正确的,那么在这种情况下实施比较的推荐方法是什么?

【问题讨论】:

  • 实现 IFieldLookup 的类是什么样的?它们是否覆盖 Equals 和/或 GetHashCode 方法?
  • @Nick - 他们没有 - 目前他们只实现 IFieldLookup 接口中的两个属性。
  • @感谢大家的反馈。

标签: c# generics


【解决方案1】:

使用 ContainsKey 并覆盖键类上的等于

好吧,假设这是我们的关键类:

class Key
{
  public int KeyValue;
  public override bool Equals(object o)
  {
    return (((Key)o).KeyValue == KeyValue);
  }
}

现在让我们使用类作为键

Dictonary<Key, string> dict = new Dictonary<Key, string>();
Key k = new Key();
k.KeyValue = 123;
dict.Add(k, "Save me!");
Key k2 = new Key();
k2.KeyValue = 123;
if (dict.ContainsKey(k2))
{
  string value = dict[k2];
}

【讨论】:

  • 这里重要的是“覆盖等于”部分。
  • @Petoj - 你说要使用 ContainsKey - 你能解释一下吗?您是否推荐它以便我不会得到例外?如果是这种情况,我希望在这种情况下例外。
  • -1:改用IEqualityComparer&lt;T&gt;
【解决方案2】:

由于这是一个接口而不是一个类,因此您必须为实现该接口的每个类定义相等运算符。这些运营商需要始终如一地运营。 (如果它是一个类而不是一个接口,那就更好了。)

您必须覆盖每个类的Equals(object)GetHashCode() 方法。

大概是这样的:

public override bool Equals(object obj)
{
   IFieldLookup other = obj as IFieldLookup;
   if (other == null)
        return false;
   return other.FileName.Equals(this.FileName) && other.FieldName.Equals(this.FieldName);
}

public override int GetHashCode()
{
    return FileName.GetHashCode() + FieldName.GetHashCode();
}

或者这个:

public override bool Equals(object obj)
{
   IFieldLookup other = obj as IFieldLookup;
   if (other == null)
        return false;
   return other.FileName.Equals(this.FileName, StringComparison.InvariantCultureIgnoreCase) && other.FieldName.Equals(this.FieldName, StringComparison.InvariantCultureIgnoreCase);
}

public override int GetHashCode()
{
    return StringComparer.InvariantCulture.GetHashCode(FileName) +
           StringComparer.InvariantCulture.GetHashCode(FieldName);
}

取决于您希望它的行为方式。

【讨论】:

  • -1:由于比较是特定于该词典的,因此请改用必要的IEqualityComparer&lt;T&gt;
  • @280Z28 - OP 没有说明比较将特定于该字典。比较很可能在程序中还有其他用途,并且这些用途的语义需要相同..
  • 我明白@Jeffrey 和@280Z28 的意思。 IEquatable 的 MSDN 页面的摘录很好地总结了它: IEquatable)>) 接口定义了类型本身的相等性,而 IEqualityComparer)>)接口在类型之外,并且允许许多不同的实现用于同一类型。谢谢你们的意见。
  • 请编辑您的答案,以便我重新为您投票 - 我点击错误。
【解决方案3】:

为键类型实现IEqualityComparer&lt;T&gt; 的实例(推荐从EqualityComparer&lt;T&gt; 派生,以便自动实现IEqualityComparer),并将实例传递给字典构造函数。这样您就可以在接口的多个实现中一致地实现比较。

【讨论】:

  • -1 这冒着在不涉及此特定字典的操作中使用不一致相等比较器的风险。
  • @280Z28 - 在阅读了这些接口之后,我看到 MSDN 说 EqualityComparer).Default 属性:“检查类型 T 是否实现 System.IEquatable 通用接口,如果因此,返回一个包含 IEquitableEquals 方法植入的 EqualityComparer)。否则,它返回一个由 T 提供的 EqualityComparer)。所以我猜想做的适当的事情是实现 IEquatable 并使用 EqualityComparer.Default ,如果需要不同的比较,然后从 EqualityComparer 派生?
  • 对于这个字典,你不会使用默认的EqualityComparer&lt;T&gt; - 如果你没有指定一个自定义的比较器,这就是Dictionary&lt;T,K&gt; 使用的。
猜你喜欢
  • 2015-03-01
  • 2021-04-04
  • 1970-01-01
  • 2018-09-27
  • 2020-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多