久々です。
で、今回は「4.3 TryGetでtryブロック追放」からでした
Dictionaryクラスはキーがない場合は例外が発生するので、TryGetValueを使いましょうね。という話です。特に異議なし。
# そもそもなんでこんなテーマ?と思い巡らせていたら、
# その昔、C#にGenericがなかったころの連想配列であるHashTableは
# キーがない場合にnullを返してたということを思い出したw。
TryGetValueの使い方的には下記通り。ContainsKeyした後に値を取得するのと同等の処理が1メソッドで実行可能です。
var dic = new Dictionary<int, string>(); string result; if (dic.TryGetValue(2, out result)) { // dictionaryに含まれていた場合の処理。 }
TryGetValueには、個人的に気に入らない点があって、out用の変数を前もって宣言しないといけないところです。このせいで、ラムダ式がExpression-Body形式でかけなかったりと割と不便なんですよね。
まぁ、この点はC#7で改善されるらしいので期待。
変数宣言式 ~ xin9le.net
http://blog.xin9le.net/entry/2016/06/29/234111
# ところで、変数のスコープが広くなるのって誰がうれしいんだろう?って思ったりしてます。
というわけで、現状はTryGetValueを使うことになるのですが、あまり便利じゃないので拡張メソッドで各種便利にしようって試み。
その① あったら取得、なかったら追加して取得。
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, Func<TKey, TValue> func) { TValue result; if (!source.TryGetValue(key, out result)) { result = func(key); source[key] = result; } return result; }
割とよくあるシチュエーションですので、こういう拡張メソッドがあれば便利かもですね。でも、最近はスレッドセーフなConcurrentDictionaryを使う一択な気もします。最初からGetOrAddメソッドが用意されています。
その② なかったらデフォルト値を返却。
public static TValue GetValueOrDefalut<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, TValue defaultValue = default(TValue)) { TValue result; return source.TryGetValue(key, out result) ? result : defaultValue; } public static TValue GetValueOrDefalut<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, Func<TKey, TValue> func) { TValue result; return source.TryGetValue(key, out result) ? result : func(key); }
これも割とありがちですね。即値を返すメソッドとデリゲートを引数に取るメソッドの2つ用意しておくと便利です。
その③ 値があったら実行
public static void GetValueAndDo<TKey, TValue>(this Dictionary<TKey, TValue> source, TKey key, Action<TValue> action) { TValue result; if (source.TryGetValue(key, out result)) { action(result); } }
②とほぼ同じ。戻値を使って何かしたいケースですね。
大体これぐらいあれば、何とかなるんじゃないでしょうか?((適当
話は変わって、Dictionary系の拡張メソッドを作る場合の注意点というか面倒くさい点があってですね。
// IDictionary型に対して拡張メソッドを定義する public static void DicExt<TKey, TValue>(this IDictionary<TKey, TValue> source); // IReadOnlyDictionary型はIDictionary型と継承関係がないので別途定義が必要 public static void DicExt<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> source); // DictionaryとConcurrentDictionaryは、上記2つのどちらのインターフェースも実装しているので // 使用する拡張メソッドが解決しないため、個別に拡張メソッドが必要になる public static void DicExt<TKey, TValue>(this Dictionary<TKey, TValue> source); public static void DicExt<TKey, TValue>(this ConcurrentDictionary<TKey, TValue> source);
と、同じ中身のメソッドを山程定義せにゃならんのですよ。なんかいい解決方法ないですかね?
コメントを残す