17

私は多くのことで自分自身を見つけるマイナーな煩わしさがあります-Dictionary<TKey, TValue>そこにあるかもしれないし、ないかもしれない値を含む を持っています。

したがって、通常の動作は、次のようにインデクサーを使用することです。

object result = myDictionary["key"];  

ただし、"key"が辞書にない場合は がスローされるKeyNotFoundExceptionため、代わりに次のようにします。

object val;
if (!myDictionary.TryGetValue("key", out val))
{
    val = ifNotFound;
}

これは問題ありませんが、これらを連続して大量に保持できることを除けば、TryGetValueひどく不格好に感じ始めます。

したがって、オプション 1 は拡張メソッドです。

public static TValue TryGet<TKey, TValue>(
    this Dictionary<TKey, TValue> input, 
    TKey key, 
    TValue ifNotFound = default(TValue))
{
    TValue val;
    if (input.TryGetValue(key, out val))
    {
        return val;
    }

    return ifNotFound;
}

これにより、次のことができます。

object result = myDictionary.TryGet("key1") ?? ifNotFound;

int i = anotherDictionary.TryGet("key2", -1);

これは単純ですが、既存のインスタンス メソッドに似た名前の拡張メソッドを追加すると、混乱が生じ、保守性が低下する可能性があります。また、欠落しているキーを処理するディクショナリのインデクサー セットとも一致しません。

したがって、オプション 2 は、IDictionary<TKey, TValue>からの暗黙的なキャストを使用したの新しい実装ですが、をスローする代わりにDictionary<TKey, TValue>返すインデクサーです。default(TValue)KeyNotFoundException

それは私にやらせてください:

ForgivingDictionary<string, object> dict = myDictionary;

object val = dict["key"] ?? ifNotFound;

// do stuff to val, then...
dict["key"] = val;

そのため、get 値と set 値は一貫していますが、値の型はより複雑で、ForgivingDictionaryより多くのコードが必要になります。

どちらの方法も「面倒」に見えます-.Netでこれを行うより良い方法はありますか?

どちらの方法も妥協して混乱を招く可能性がありますが、一方が他方より明白/明確ですか? なぜ?

4

3 に答える 3

8

既存のメソッドを置き換えることを目的とした拡張メソッドに名前を付けるとき、私はそれを短縮するのではなく、具体性のためにメソッド名に追加する傾向があります。

GetValueOrDefault(...)

については、値型にならないようにForgivingDictionary制約することができます。TKeyただし、その中の値型を処理する必要がある場合は、値型に対して何かを返すことになります。default(TKey)返すことができないため、返すのが最善のオプションですnull

正直なところ、私は拡張メソッドを使用します。

編集GetValueOrDefault()もちろん、キーが見つからない場合は辞書に追加されません。見つからなかった場合はデフォルト値を返すだけです。これがその名前の付け方だからです。挿入したい場合は、良い名前になりますGetValueOrInsertDefault()

于 2011-06-02T13:49:33.863 に答える
1

キーが見つからない場合に何をすべきか、あなたの質問から推測することはできません。その場合は何もしなくてよいことも想像できますが、その逆も想像できます。とにかく、あなたが説明するこれらの一連の TryGetValue ステートメントのエレガントな代替手段は、次の拡張メソッドのいずれかを使用することです。辞書にキーが含まれていない場合に何かを行う必要があるかどうかに応じて、2 つのオプションを用意しました。

/// <summary> Iterates over all values corresponding to the specified keys, 
///for which the key is found in the dictionary. </summary>
public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys)
{
    TValue value;
    foreach (TKey key in keys)
        if (dictionary.TryGetValue(key, out value))
            yield return value;
}

/// <summary> Iterates over all values corresponding to the specified keys, 
///for which the key is found in the dictionary. A function can be specified to handle not finding a key. </summary>
public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys, Action<TKey> notFoundHandler)
{
    TValue value;
    foreach (TKey key in keys)
        if (dictionary.TryGetValue(key, out value))
            yield return value;
        else
            notFoundHandler(key);                        
}

これを使用する方法のコード例は次のとおりです。

TKey[] keys = new TKey{...};
foreach(TValue value in dictionary.TryGetValues(keys))
{
    //some action on all values here
}
于 2011-06-02T13:38:26.830 に答える
0

多分

public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> input, 
                                                   TKey key)
{

     return input.ContainsKey(key) ? input[key] : *some default value*;

}
于 2011-06-03T12:52:25.337 に答える