C# 如何检查字典是否已经有键';x';?

C# 如何检查字典是否已经有键';x';?,c#,dictionary,key,C#,Dictionary,Key,我尝试使用C#字典实现简单算法: 我的“外部”字典如下所示:字典[其中paramID只是一个包含两个字符串的标识符] 如果键“x”已经在字典中,则将特定条目添加到此记录的字典中;如果它不存在,则将其条目添加到外部字典中,然后将条目添加到内部字典中 不知何故,当我使用TryGetValue时,它总是返回false,因此它总是在外部字典中创建新的条目——这会产生重复项 我的代码大致如下所示: Dictionary<string, object> tempDict = new Di

我尝试使用C#字典实现简单算法:

我的“外部”字典如下所示:
字典
[其中paramID只是一个包含两个字符串的标识符]

如果键“x”已经在字典中,则将特定条目添加到此记录的字典中;如果它不存在,则将其条目添加到外部字典中,然后将条目添加到内部字典中

不知何故,当我使用TryGetValue时,它总是返回false,因此它总是在外部字典中创建新的条目——这会产生重复项

我的代码大致如下所示:

    Dictionary<string, object> tempDict = new Dictionary<string, object>();

    if(outerDict.TryGetValue(new paramID(xKey, xValue), out tempDict))
    {
     tempDict.Add(newKey, newValue);
    } 
Dictionary tempDict=newdictionary();
if(outerDict.TryGetValue(新参数ID(xKey,xValue),out tempDict))
{
tempDict.Add(newKey,newValue);
} 
如果从未执行,则在
内执行块,即使外部字典中有此特定条目

我错过什么了吗?(如果您愿意,我可以发布调试器的屏幕截图,或者您需要的其他内容)

使用

因此:

Dictionary<string, object> tempDict = new Dictionary<string, object>();

paramID searchKey = new paramID(xKey, xValue);
if(outerDict.ContainsKey(searchKey))
{  
   outerDict.TryGetValue(searchKey, out tempDict);
   tempDict.Add(newKey, newValue);
} 
使用

因此:

Dictionary<string, object> tempDict = new Dictionary<string, object>();

paramID searchKey = new paramID(xKey, xValue);
if(outerDict.ContainsKey(searchKey))
{  
   outerDict.TryGetValue(searchKey, out tempDict);
   tempDict.Add(newKey, newValue);
} 

最有可能的是,
paramID
无法正确实现相等比较。

它应该实现
IEquatable
,这意味着实现必须遵守要求(请参见“实现者注意事项”)

至于字典中的键,MSDN说:

只要一个对象被用作字典中的键(对于TKey, TValue),它不得以任何影响其哈希值的方式进行更改。 字典中的每个键(TKey,TValue)都必须是唯一的 字典的等式比较器。钥匙不可能什么都不是,而是一把钥匙 如果值类型TValue是引用类型,则值可以是

字典(TKey,TValue的)需要一个相等实现来 确定键是否相等。您可以指定 IEqualityComparer(Of T)通过使用构造函数创建通用接口 接受比较器参数的;如果未指定 实现,默认的通用相等比较器 EqualityComparer(属于T)。使用默认值。如果类型TKey实现 System.IEquatable(Of T)通用接口,默认相等 比较器使用该实现

由于您没有显示
paramID
类型,因此我无法详细介绍


顺便说一句:这里有很多键和值纠结在一起。字典内部有一个字典,外部字典的键也聚合了某种值。也许可以有利地简化这种安排?您到底想实现什么?

最有可能的是,
paramID
没有正确实现相等比较。

它应该实现
IEquatable
,这意味着实现必须遵守要求(请参见“实现者注意事项”)

至于字典中的键,MSDN说:

只要一个对象被用作字典中的键(对于TKey, TValue),它不得以任何影响其哈希值的方式进行更改。 字典中的每个键(TKey,TValue)都必须是唯一的 字典的等式比较器。钥匙不可能什么都不是,而是一把钥匙 如果值类型TValue是引用类型,则值可以是

字典(TKey,TValue的)需要一个相等实现来 确定键是否相等。您可以指定 IEqualityComparer(Of T)通过使用构造函数创建通用接口 接受比较器参数的;如果未指定 实现,默认的通用相等比较器 EqualityComparer(属于T)。使用默认值。如果类型TKey实现 System.IEquatable(Of T)通用接口,默认相等 比较器使用该实现

由于您没有显示
paramID
类型,因此我无法详细介绍


顺便说一句:这里有很多键和值纠结在一起。字典内部有一个字典,外部字典的键也聚合了某种值。也许可以有利地简化这种安排?您到底想实现什么?

如果您没有在paramID类型上过度使用equals和GetHashCode,并且它是一个类而不是一个结构,那么默认的相等含义将生效,并且每个paramID将只与自身相等

您可能需要以下内容:

public class ParamID : IEquatable<ParamID> // IEquatable makes this faster
{
  private readonly string _first; //not necessary, but immutability of keys prevents other possible bugs
  private readonly string _second;
  public ParamID(string first, string second)
  {
    _first = first;
    _second = second;
  }
  public bool Equals(ParamID other)
  {
    //change for case-insensitive, culture-aware, etc.
    return other != null && _first == other._first && _second == other._second;
  }
  public override bool Equals(object other)
  {
    return Equals(other as ParamID);
  }
  public override int GetHashCode()
  {
    //change for case-insensitive, culture-aware, etc.
    int fHash = _first.GetHashCode();
    return ((fHash << 16) | (fHash >> 16)) ^ _second.GetHashCode();
  }
}
此时,如果我们执行以下操作:

ParamID x = new ParamID("a", "b");
ParamID y = new ParamID("a", "b");
ParamID z = x;
bool a = x == y;//a is false
bool b = z == x;//b is true
因为默认情况下,引用类型仅与自身相等。为什么?首先,有时这正是我们想要的,其次,如果程序员不定义平等的工作方式,我们可能并不总是清楚我们还想要什么

另外请注意,如果ParamID是一个结构,那么它将定义与您想要的非常相似的等式。然而,实现效率很低,如果它包含一个十进制数,也会出现问题,因此无论哪种方式,显式实现相等总是一个好主意

我们要给它一个不同的平等概念,首先要做的是覆盖
IEquatable
。这并不是绝对必要的,(直到.NET 2.0才存在),但是:

  • 在许多用例中,它都会更有效,包括在键入
    字典时
  • 以这一点为出发点进行下一步很容易
  • 现在,我们在实施平等概念时必须遵循四条规则:

  • 对象必须始终与自身相等
  • 如果X==Y和X!=Z、 然后,如果这些对象的状态都没有改变,那么X==Y和X!=Z仍然是
  • 如果X==Y和Y==Z,那么X==Z
  • 如果X==Y和Y!=Z然后X!=Z
  • 大多数时候,你都会不假思索地遵循这些规则,你只需检查它们是否正确
    ParamID x = new ParamID("a", "b");
    ParamID y = new ParamID("a", "b");
    ParamID z = x;
    bool a = x == y;//a is false
    bool b = z == x;//b is true
    
    public class ParamID : IEquatable<ParamID>
    {
      private readonly string _first; //not necessary, but immutability of keys prevents other possible bugs
      private readonly string _second;
      public ParamID(string first, string second)
      {
        _first = first;
        _second = second;
      }
      public bool Equals(ParamID other)
      {
        if(other == null)
          return false;
        if(ReferenceEquals(this, other))
          return true;
        if(string.Compare(_first, other._first, StringComparison.InvariantCultureIgnoreCase) == 0 && string.Compare(_second, other._second, StringComparison.InvariantCultureIgnoreCase) == 0)
          return true;
        return string.Compare(_first, other._second, StringComparison.InvariantCultureIgnoreCase) == 0 && string.Compare(_second, other._first, StringComparison.InvariantCultureIgnoreCase) == 0;
      }
    }
    
    public override bool Equals(object other)
    {
      return (other as ParamID);
    }
    
    ParamID x = new ParamID("a", "b");
    dict.Add(x, 33);
    x.First = "c";//x will now likely never be found in dict because its hashcode doesn't match its position!
    
    public override int GetHashCode()
    {
      return StringComparer.OrdinalIgnoreCase.GetHashCode(_first) ^ StringComparer.OrdinalIgnoreCase.GetHashCode(_second);
    }