LoginSignup
20
28

More than 3 years have passed since last update.

keyが存在しない場合はデフォルト値を返すDictionaryの拡張

Last updated at Posted at 2017-05-29

keyが存在しない場合はデフォルト値を返すDictionaryのメソッド

ってなんで無いんでしょうかね。

普通に、アクセスしようとすると

var dict = new Dictionary<string,string>();
var t = dict["test"];//↑で作ったばかりなので入ってるはずもなく、KeyNotFoundException

この時点でnull返してくれたりすればいいのになぁ。と思わなくもないんですが。

まぁ、想像するとまだnullableが無かったころの名残なのかな。と。
stringみたいな参照型ならいいけれど、Dictionary<string,int>みたいに、Valueがプリミティブ型だった場合に0返したとしてそれが本当のValueの0なのか、Keyが無かったからデフォルト値の0なのかが判別つかないからかな。
いや、そもそも、参照型だとしても明示的にvalueにnull入れる場合もあるので・・・?
そう考えると無いのもしょうがないな。とは思います。が、不便なものは不便。

一応、先にContainsKeyでKeyの存在チェックをしたり、TryGetValueする。という手もあるんですが、無駄に行数はかさむし、直感的じゃなかったりするので、ここは拡張メソッドの出番でしょう。

こんな拡張クラスを作っておくと便利

public static class DictionaryExtensions {
    /// <summary>
    /// 値を取得、keyがなければデフォルト値を設定し、デフォルト値を取得
    /// </summary>
    public static TV GetOrDefault<TK, TV>(this Dictionary<TK, TV> dic, TK key,TV defaultValue = default(TV))
    {
        TV result;
        return dic.TryGetValue(key, out result) ? result : defaultValue;
    }
}

DictionaryにGetOrDefaultという名前のメソッドを拡張メソッドとして生やします。

これで、

var dict = new Dictionary<string,string>();
//var t = dict["test"];//↑で作ったばかりなので入ってるはずもなく、KeyNotFoundException
var t = dict.GetOrDefault("test");  //default値を指定しない場合はdefault(KV),KV=stringなので、stringのデフォ値のnullがtに入る

var t2 = dict.GetOrDefault("test2","入ってなかったよ");  //default値を明示的に指定した場合は、keyが存在しない場合にそれが使用される。

と、なり、みんなハッピーです。

2020/01/27追記

C#7.0 から out var(out変数宣言) が使えるので、上記 TryGetValue はさらに簡略化して書けるようになります。
(詳しくは→ TryGetComponentとout、out var のお話 などをどうぞ(ダイマ

public static class DictionaryExtensions {
    /// <summary>
    /// 値を取得、keyがなければデフォルト値を設定し、デフォルト値を取得
    /// </summary>
    public static TV GetOrDefault<TK, TV>(this Dictionary<TK, TV> dic, TK key,TV defaultValue = default(TV))
    {
        return dic.TryGetValue(key, out var result) ? result : defaultValue;
    }
}

単行になりました。 なら、こうも書けますね。(ついでにdefaultの書き方も変更)

public static class DictionaryExtensions {
    /// <summary>
    /// 値を取得、keyがなければデフォルト値を設定し、デフォルト値を取得
    /// </summary>
    public static TV GetOrDefault<TK, TV>(this Dictionary<TK, TV> dic, TK key,TV defaultValue = default) => dic.TryGetValue(key, out var result) ? result : defaultValue;
}

まぁ、(多分)速度に違いはないのであとは見やすさ、わかりやすさ。そして場合によってはチームの規約に従うしかないのでTPOに応じて適切なものを使いましょう。
ではでは。

20
28
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
28