82

I am using a dictionary to perform lookups for a program I am working on. I run a bunch of keys through the dictionary, and I expect some keys to not have a value. I catch the KeyNotFoundException right where it occurs, and absorb it. All other exceptions will propagate to the top. Is this the best way to handle this? Or should I use a different lookup? The dictionary uses an int as its key, and a custom class as its value.

Mediator
  • 14,951
  • 35
  • 113
  • 191
Dan McClain
  • 11,780
  • 9
  • 47
  • 67

6 Answers6

151

Use Dictionary.TryGetValue instead:

Dictionary<int,string> dictionary = new Dictionary<int,string>();
int key = 0;
dictionary[key] = "Yes";

string value;
if (dictionary.TryGetValue(key, out value))
{
    Console.WriteLine("Fetched value: {0}", value);
}
else
{
    Console.WriteLine("No such key: {0}", key);
}
Avi Turner
  • 10,234
  • 7
  • 48
  • 75
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Is this still adviced instead of ContainsKey()? – Sven van den Boogaart Feb 23 '17 at 13:20
  • 5
    @SvenB: Yes, I'd say so. Why do the lookup twice, once to check for the key existence and then once to get the value, when you can do them both at the same time? – Jon Skeet Feb 23 '17 at 15:11
  • @JonSkeet I dont know my guess would be to avoid an unnecessary assignment if containskey is false. – Sven van den Boogaart Feb 23 '17 at 17:02
  • 2
    @SvenB: Compare one unnecessary assignment with the cost of performing the whole lookup again if ContainsKey is true... I would be astonished to find any real-world example where that's more efficient. – Jon Skeet Feb 23 '17 at 17:11
  • @JonSkeet thank you for the answer, I have an api where i have a dictionary (tablename,tableid) where based on the url the tableid is requested (api/{tablename}) the chance is bigger that an url is requested without a valid tablename than with one (so trygetvalue will fail more often than not) would trygetvalue be more efficient than containskey() ( I know it wont matter much but im interested in the answer) – Sven van den Boogaart Feb 23 '17 at 17:31
  • 3
    @JonSkeet Now that the new version of dot.net is out, maybe update the answer and put the `string value` as part of the TryGetValue: `if (dictionary.TryGetValue(key, out string value))` – Blue Sep 23 '17 at 04:55
  • 1
    @FrankerZ I'm not sure it's worth doing that on old answers - especially as many users won't be using C# 7 yet. – Jon Skeet Sep 23 '17 at 06:27
39

Try using: Dict.ContainsKey

Edit:
Performance wise i think Dictionary.TryGetValue is better as some other suggested but i don't like to use Out when i don't have to so in my opinion ContainsKey is more readable but requires more lines of code if you need the value also.

Peter
  • 37,042
  • 39
  • 142
  • 198
  • 1
    Why did it get a downvote? please explain so i can improve the answer. – Peter Sep 08 '14 at 06:18
  • 1
    Could you explain why you don't like to use `out` unless you have to? –  Aug 26 '15 at 13:51
  • 3
    @wilbishardis its just a habit, in my opinion i think its harder to miss that a method parameter can be modified its much clearer when you have a = sign. now this is just my opinion and that doesn't mean everybody feels the same, and in some cases its the best option `int.TryParse` is one example.. – Peter Oct 05 '15 at 06:16
35

One line solution using TryGetValue

string value = dictionary.TryGetValue(key, out value) ? value : "No key!";

Be aware that value variable must be of type which dictionary returns in this case string. Here you can not use var for variable declaration.

If you are using C# 7, in which case you CAN include the var and define it inline:

string value = dictionary.TryGetValue(key, out var tmp) ? tmp : "No key!";

Here is also nice extension method which will do exactly what you want to achieve dict.GetOrDefault("Key") or dict.GetOrDefault("Key", "No value")

public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue = default(TValue))
{
      if (dictionary != null && dictionary.ContainsKey(key))
      {
           return dictionary[key];
      }
      return defaultValue;
 }
Jernej Novak
  • 3,165
  • 1
  • 33
  • 43
16

Here is a one line solution (Keep in mind this makes the lookup twice. See below for the tryGetValue version of this which should be used in long-running loops.)

string value = dictionary.ContainsKey(key) ? dictionary[key] : "default";

Yet I find myself having to do this everytime I access a dictionary. I would prefer it return null so I can just write:

string value = dictionary[key] ?? "default";//this doesn't work
MondayPaper
  • 1,569
  • 1
  • 15
  • 20
  • 2
    Avoid using this solution as it requires two lookups on the dictionary. One lookup for `dictionary.ContainsKey` and another for `dictionary[key]`. Use @JernejNovak's answer for better performance. – Blue Aug 21 '17 at 09:51
  • Sometimes performance isn't a priority and readability is more important. Jon Skeet's answer isn't something you want scattered all over your code. I would say avoid this in large loops. I'll make a note in my answer. Not really worth the downvote though. – MondayPaper Sep 22 '17 at 19:31
  • How is `string value = dictionary.ContainsKey(key) ? dictionary[key] : "default";` more readable than `string value = dictionary.TryGetValue(key, out value) ? value : "No key!";` – Blue Sep 23 '17 at 03:59
  • 4
    Dude... When I wrote this answer there was no answer below (It was over a year before). Which is why I compared my answer to Jon Skeets answer. Secondly out values can be harder to read. The user may not know that you can't use var to initialize the value and it's not immediately clear that value will be initialized before it's set. It's a great solution and I'll use it going forward, but it's tricky (it works by setting value to itself again after it was already set in the out)... and that's probably why it took someone over a year to add a better solution. – MondayPaper Oct 04 '17 at 20:22
  • Even after knowing the solution with TryGetValue, I still find MondayPaper's solution nicer. But I really don't understand why C# doesn't just return "null" if it can't find a value for a certain key. It makes it so frustrating to work with this language... – Andreas Utzinger Jun 28 '22 at 14:46
6

I know this is an old thread but in case it's helpful the prior answers are great, but the comments of complexity and concerns of littering the code (all valid for me also) can be addressed.

I use a custom extension method to wrap up the complexity of the above answers in a more elegant form so that it's not littered throughout the code, and it then enables great support for null coalesce operator . . . while also maximizing performance (via above answers).

namespace System.Collections.Generic.CustomExtensions
{
    public static class DictionaryCustomExtensions
    {
        public static TValue GetValueSafely<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            TValue value = default(TValue);
            dictionary.TryGetValue(key, out value);
            return value;
        }
    }
}

Then you can use it simply by importing the namespace System.Collections.Generic.CustomExtensions

string value = dictionary.GetValueSafely(key) ?? "default";
CajunCoding
  • 720
  • 5
  • 9
5

you should use the 'ContainsKey(string key)' method of the Dictionary to check if a key exists. using exceptions for normal program flow is not considered a good practice.

Remco Ros
  • 1,467
  • 15
  • 31