C#字典不抛出KeyNotFound异常?

时间:2019-05-24 12:58:46

标签: c# dictionary

为什么此代码不引发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}");
        }

Output

2 个答案:

答案 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