Это потому, что Dictionary<TKey, TValue>
реализует как c версию generic *, так и c версию non-generi (просто IDictionary
, которая дает Object
).
Looking в источнике можно легко увидеть, что индексатор универсального c версии явно выбрасывает, когда ключ не найден:
public TValue this[TKey key]
{
get
{
int i = FindEntry(key);
if (i >= 0) return entries[i].value;
ThrowHelper.ThrowKeyNotFoundException(); // <-- this line
return default(TValue);
}
}
Но не является универсальным c версия не:
object IDictionary.this[object key]
{
get
{
if (IsCompatibleKey(key))
{
int i = FindEntry((TKey)key);
if (i >= 0)
return entries[i].value;
}
return null;
}
}
Тогда, если вы явно не приведете свой Dictionary
к не-универсальной c версии, вы вызываете индексатор, который выдает, когда ключ не найден.
Обновление (согласно вашему комментарию):
С тех пор как IDictionary
(версия non-generi c) была введена в. NET 1.0 (когда еще не было поддержки дженериков), единственный тип, который он потреблял и возвращал, это, очевидно, System.Object
(который можно проверить на null
).
Следовательно, имеет смысл не бросать, когда ключ не найден, потому что можно просто сделать это:
dict["nonExistingKey"] != null
Но как только генерит c IDictionary<TKey, TValue>
был введен, TValue
также может быть установлен на тип значения (например, int
или DateTime
), и приведенный выше шаблон должен быть настроен на:
var dict = new Dictionary<string, int>();
dict["nonExistingKey"] != 0;
dict["nonExistingKey"] != default(int);
, который менее плавный, менее стандартный и более громоздкий в использовании.
С "точки зрения дизайна", я полагаю, они решили сохранить обратную совместимость для IDictionary
, в то же время упреждающе выбрасывая для универсальной c версии.