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