15

Currently I'm using

var x = dict.ContainsKey(key) ? dict[key] : defaultValue

I'd like some way to have dictionary[key] return null for nonexistant keys, so I could write something like

var x =  dict[key] ?? defaultValue;

this also winds up being part of linq queries etc. so I'd prefer one-line solutions.

Jimmy
  • 89,068
  • 17
  • 119
  • 137
  • The current answers are correct, and see also [my similar question](http://stackoverflow.com/questions/6214975), which is more of a discussion. However you should avoid `dict.ContainsKey(key) ? dict[key]` as you're looking up the dictionary twice, once for the `ContainsKey` and again for the `[]` indexer. `TryGetValue` is ugly and non-inline, but it is a single operation. – Keith May 07 '13 at 11:03

4 Answers4

21

With an extension method:

public static class MyHelper
{
    public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dic, 
                                            K key, 
                                            V defaultVal = default(V))
    {
        V ret;
        bool found = dic.TryGetValue(key, out ret);
        if (found) { return ret; }
        return defaultVal;
    }
    void Example()
    {
        var dict = new Dictionary<int, string>();
        dict.GetValueOrDefault(42, "default");
    }
}
Omer Mor
  • 5,216
  • 2
  • 34
  • 39
Brian
  • 117,631
  • 17
  • 236
  • 300
  • 4
    I'd offer an overload that returns default(V) –  Oct 31 '08 at 17:04
  • 4
    In C#4 you can now make the default parameter optional: V defaultVal = default(V). Then you don't have to pass in a default if you don't want to - if the value isn't found, you'll get the default for the type V. – Tevin Mar 10 '11 at 13:23
  • @Tevin can you provide a link to msdn/article that documents this behaviour ? I'm not familiar with .NET 4, but the default-operator on a reference type in .NET 3.5 returns null and default on a value type returns the value using the no-args constructor. I doubt this has changed ? – toong Feb 09 '12 at 21:46
  • For the benefit of people coming through later, in addition to the first two comments, there are also many more common IDictionary implementations like ConcurrentDictionary so using the IDictionary interface instead of the Dictionary class will help in a wider range of situations. – jnm2 Jun 27 '13 at 20:33
  • The beauty of the default parameter is that you have three syntactic options. 1) Shorthand for the cases where you intend null, 2) a specific default parameter, and 3) the option to coalesce if you prefer: dict.GetValueOrDefault(key) ?? defaultObj; – jnm2 Jun 27 '13 at 20:40
6

You can use a helper method:

public abstract class MyHelper {
    public static V GetValueOrDefault<K,V>( Dictionary<K,V> dic, K key ) {
        V ret;
        bool found = dic.TryGetValue( key, out ret );
        if ( found ) { return ret; }
        return default(V);
    }
}

var x = MyHelper.GetValueOrDefault( dic, key );
TcKs
  • 25,849
  • 11
  • 66
  • 104
  • You can also trivially make that an extension method, so you can do dict.GetValueOrDefault( key ) – stevemegson Oct 31 '08 at 17:00
  • I thought he did that in the first place... Odd that the only difference would be the 'this' keyword. –  Oct 31 '08 at 17:01
  • 3
    You can actually make this unconditional - just return ret after the call to TryGetValue. It will default(V) if the method returns false. – Jon Skeet Oct 31 '08 at 17:09
  • @Jon - good point.. however, I would advocate making this an extension method on the interface `IDictionary` rather than `Dictionary` and some weird (semantically wrong) implementation might return something other than default(V) – Adam Ralph Oct 29 '10 at 13:44
5

Here is the "ultimate" solution, in that it is implemented as an extension method, uses the IDictionary interface, provides an optional default value, and is written concisely.

public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> dic, TK key,
    TV defaultVal=default(TV))
{
    TV val;
    return dic.TryGetValue(key, out val) 
        ? val 
        : defaultVal;
}
Mike Chamberlain
  • 39,692
  • 27
  • 110
  • 158
0

Isn't simply TryGetValue(key, out value) what you are looking for? Quoting MSDN:

When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.

from http://msdn.microsoft.com/en-us/library/bb347013(v=vs.90).aspx

Matt Connolly
  • 9,757
  • 2
  • 65
  • 61
  • I was looking for a single-line expression. The issue with `TryGetValue` is that 1) it is a statement. 2) it requires a preceding declaration of the `out` variable. – Jimmy May 25 '12 at 21:21