为什么此代码不引发KeyNotFound异常?
var tempDic = new Dictionary<long, string>{{1,"a"},{2,"b"},{3,"c"}};
var realDic = new Dictionary<long, string>{{1,"Z"}};
Console.WriteLine("BEFORE:");
foreach (var item in tempDic)
{
Console.WriteLine($"TempDic: {item.Key} : {item.Value}");
}
foreach (var item in realDic)
{
Console.WriteLine($"realDic: {item.Key} : {item.Value}");
}
foreach (var key in tempDic.Keys)
{
if (!realDic.ContainsKey(key))
{
realDic[key] = tempDic[key];
}
}
Console.WriteLine();
Console.WriteLine("AFTER:");
foreach (var item in tempDic)
{
Console.WriteLine($"TempDic: {item.Key} : {item.Value}");
}
foreach (var item in realDic)
{
Console.WriteLine($"realDic: {item.Key} : {item.Value}");
}
答案 0 :(得分:2)
在词典中,realDic[key] = tempDic[key];
是realDic.Add(key, tempDic[key]);
的另一种表达方式。
这就是为什么不抛出KeyNotFoundException
的原因。
在MSDN documentation, regarding Add
method, "Remarks" section中有解释,但还是有所不同:
您还可以使用
Item[TKey]
属性通过以下方式添加新元素 设置不存在的键的值 例如Dictionary<TKey,TValue>;
,myCollection[myKey] = myValue
(在Visual Basic中,myCollection(myKey) = myValue
)。但是,如果 指定的密钥已经存在于Dictionary<TKey,TValue>
中,设置Item[TKey]
属性将覆盖旧值。相反, 添加 如果具有指定键的值已存在,则方法将引发异常 存在。
答案 1 :(得分:0)
看Dictionary<TKey,TValue>
source code。
索引器看起来像这样(记住,您将其称为二传手):
public TValue this[TKey key] {
get {
int i = FindEntry(key);
if (i >= 0) return entries[i].value;
ThrowHelper.ThrowKeyNotFoundException();
return default(TValue);
}
set {
Insert(key, value, false);
}
}
其中Insert
是:
private void Insert(TKey key, TValue value, bool add) {
if( key == null ) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
}
if (buckets == null) Initialize(0);
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
int targetBucket = hashCode % buckets.Length;
#if FEATURE_RANDOMIZED_STRING_HASHING
int collisionCount = 0;
#endif
for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next) {
if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) {
if (add) {
ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
}
entries[i].value = value;
version++;
return;
}
#if FEATURE_RANDOMIZED_STRING_HASHING
collisionCount++;
#endif
}
int index;
if (freeCount > 0) {
index = freeList;
freeList = entries[index].next;
freeCount--;
}
else {
if (count == entries.Length)
{
Resize();
targetBucket = hashCode % buckets.Length;
}
index = count;
count++;
}
entries[index].hashCode = hashCode;
entries[index].next = buckets[targetBucket];
entries[index].key = key;
entries[index].value = value;
buckets[targetBucket] = index;
version++;
#if FEATURE_RANDOMIZED_STRING_HASHING
#if FEATURE_CORECLR
// In case we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
// in this case will be EqualityComparer<string>.Default.
// Note, randomized string hashing is turned on by default on coreclr so EqualityComparer<string>.Default will
// be using randomized string hashing
if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default)
{
comparer = (IEqualityComparer<TKey>) EqualityComparer<string>.Default;
Resize(entries.Length, true);
}
#else
if(collisionCount > HashHelpers.HashCollisionThreshold && HashHelpers.IsWellKnownEqualityComparer(comparer))
{
comparer = (IEqualityComparer<TKey>) HashHelpers.GetRandomizedEqualityComparer(comparer);
Resize(entries.Length, true);
}
#endif // FEATURE_CORECLR
#endif
}
它给出您观察到的行为。如果key
不存在,则会添加它并设置相应的value
。