Даний ключ відсутній у словнику. Який ключ?


78

Чи є спосіб отримати значення даного ключа в наступному винятку в C # таким чином, що впливає на всі загальні класи? Я думаю, це велика помилка в описі винятків від Microsoft.

"The given key was not present in the dictionary."

Кращим способом буде:

"The given key '" + key.ToString() + "' was not present in the dictionary."

Рішення можуть включати міксини або похідні класи, можливо.


13
Це питання, здається, не стосується теми, оскільки це суперечка щодо реалізації повідомлення про виняток, а не питання програмування.
Серві

6
Проблема тут полягає в тому, що налагоджувач не завжди доступний, наприклад, під час читання файлу журналу.
Андреас,

4
Ви припускаєте, що всі словники мають ключ, де це .ToString()має сенс. Я погоджуюсь у випадку, Dictionary<string, *>що це було б гарним доповненням до опису винятків, але воно не може застосовуватися до всіх типів Dictionary<*,*>об'єктів.
demoncodemonkey

2
Ні, але навіть якщо ключ.ToString () іноді каже "Об'єкт", він все одно спрацює, можливо, у 90% випадків.
Андреас,

3
Я думаю, одна з причин, чому вона не в тому, полягає в тому, що РС абсолютно не знає, що таке ключ або чи слід його викривати. Це може бути ідентифікаційна інформація або секрет, який не слід реєструвати. Безпечніша поведінка - викривати менше деталей, коли ви не знаєте, хто їх побачить.
Mike Zboray

Відповіді:


73

Цей виняток виникає при спробі індексувати щось, чого там немає, наприклад:

Dictionary<String, String> test = new Dictionary<String,String>();
test.Add("Key1,"Value1");
string error = test["Key2"];

Часто ключовим фактором буде щось на зразок предмета, що, безсумнівно, ускладнює його отримання. Однак ви завжди можете написати наступне (або навіть обернути його способом розширення):

if (test.ContainsKey(myKey))
   return test[myKey];
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Або більш ефективний (завдяки @ScottChamberlain)

T retValue;
if (test.TryGetValue(myKey, out retValue))
    return retValue;
else
   throw new Exception(String.Format("Key {0} was not found", myKey));

Microsoft вирішила цього не робити, можливо, тому, що це було б марно, коли б використовувалось на більшості об'єктів. Це досить просто зробити самостійно, тому просто катайте свої власні!


19
Робити ContainsKeyто індексатор викличе два Lookups в словнику. Виконання a TryGetValueбуло б лише одним пошуком, і ви можете просто використовувати логічний вивід цього, щоб вибрати свій блок if / else.
Скотт Чемберлен,

1
@ScottChamberlain Дуже правда. Додано як додаткову реалізацію.
BradleyDotNET

спробуйте test.keys.contens (key), який повертає логічне значення.
Куркула

17

У загальному випадку відповідь - Ні.

Однак ви можете встановити налагоджувач, щоб він зламався в точці, де вперше виникає виняток. У той час ключ, якого не було, буде доступний як значення у стеку викликів.

У Visual Studio ця опція знаходиться тут:

Налагодження → Винятки ... → Винятки загальної мови виконання → System.Collections.Generic

Там ви можете встановити прапорець Thrown .


Для більш конкретних випадків, коли інформація потрібна під час виконання, за умови, що ваш код використовує IDictionary<TKey, TValue>і не пов’язаний безпосередньо Dictionary<TKey, TValue>, ви можете реалізувати власний клас словника, який забезпечує таку поведінку.


Зазвичай я запускаю свій налагоджувач.
AaronLS

Привіт @Sam, в який момент у стеці викликів ти знаходиш це значення?
user919426

2
VS 2017 (v15.5.7) має таке: Налагодження -> Windows -> Налаштування винятків -> потім перевірте System.Collections.Generic.KeyNotFoundException
Роберт Кох

9

Якщо ви хочете керувати пропусками клавіш, вам слід використовувати TryGetValue

https://msdn.microsoft.com/en-gb/library/bb347013(v=vs.110).aspx

string value = "";
if (openWith.TryGetValue("tif", out value))
{
    Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
    Console.WriteLine("Key = \"tif\" is not found.");
}

1
Це передбачає, що передбачається використання ключа, якого немає. Це може бути не так. Це законно може бути винятковим випадком.
Серві

1
string Value = dic.ContainsKey("Name") ? dic["Name"] : "Required Name"

За допомогою цього коду ми отримаємо рядкові дані у "Значенні". Якщо ключ 'Name' існує у словнику 'dic', тоді отримайте це значення, інакше повертає рядок "Обов'язкове ім'я".


2
Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
адіга

0

Ви можете спробувати цей код

Dictionary<string,string> AllFields = new Dictionary<string,string>();  
string value = (AllFields.TryGetValue(key, out index) ? AllFields[key] : null);

Якщо ключа немає, він просто повертає нульове значення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.