2

重複の可能性:
キーで辞書の値にアクセスする KeyNotFoundException の代わりに null を取得する方法は?

現在、プロジェクトで多くのDictionary<string, T>用途があり、そのほとんどは次のようになっています。

if (myDic.ContainsKey("some key"))
    localVar = myDic["some key"];

ディクショナリに対して 2 つの呼び出しを行うため、リソースを消費する可能性があるため、あまり効率的ではありません。TryGetValue()はクールなことですが、1 行で行うことはできません。

nullからそのようなキーがないかどうかを取得したいだけですvar v = myDic[key]。それ、どうやったら出来るの?

4

3 に答える 3

4

次の拡張メソッドを使用できますTryGetValue

public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
where U : class
{
    U value;
    dict.TryGetValue(key, out value);
    return value;
}

おかげであなたは書くことができるでしょう

somedict.GetValueByKeyOrNull("key1")

結局、これを実行しようとして、明示的なインターフェイス実装を備えたディクショナリクラスから派生したバリアントを使用するバリアントを思いつきました。KeyNotFoundExceptionがキーでディクショナリ値にアクセスする代わりにnullを取得する方法は?

あれは

public interface INullValueDictionary<T, U>
    where U : class
{
    U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
    where U : class
{
    U INullValueDictionary<T, U>.this[T key]
    {
        get
        {
            U val;
            dict.TryGet(key, out val);
            return val;
        }
    }
}

どこでも元の辞書の代わりにそれを使用してください:

//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
    {1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;
string val = idict[2]; // null
val = idict[1];        // "one"
于 2013-01-16T05:51:08.637 に答える
1

私は対処したくないnullので、実装は次のようになります。

interface Maybe<T> {
    bool HasValue {get;}
    T Value {get;}
}

class Nothing<T> : Maybe<T> {
    public bool HasValue { get { return false; } }
    public T Value { get { throw new Exception(); } }
    public static const Nothing<T> Instance = new Nothing<T>();
}

class Just<T> : Maybe<T> {
    private T _value;
    public bool HasValue { get { return true; } }
    public T Value { get { return _value; } }
    public Just(T val) {
        _value = val;
    }
}

Maybe値を含むか含まないオブジェクトです。Nothingclass には static フィールドが含まれていることに注意してくださいInstance。関数から戻る必要があるたびに新しい値を作成する代わりに、この値を使用できますNothing

ここで、独自の辞書クラスを作成する必要があります。

class MyDictionary<TKey, TValue>
{
    private Dictionary<TKey, TValue> _dict;

    ...

    public Maybe<TValue> this[TKey key] {
        TValue val;
        if (_dict.TryGetValue(key, out val)) {
            return new Just<TValue>(val);
        return Nothing<TValue>.Instance;
    }
}

C# にはパターン マッチングがないため、このアプローチの利点は明確ではありません。ただし、次の方法でエミュレートできますdynamic

void ProcessResult(Just<string> val) {
    Console.WriteLine(val);
}

void ProcessResult(Nothing<string> n) {
    Console.WriteLine("Key not found");
}

var dict = new MyDictionary<string, string>();
...
dynamic x = dict["key"];
ProcessResult(x);

これは、辞書が常に意味のある結果を返すとは限らないという事実を表現する非常に明確な方法だと思います。また、関数のオーバーロードProcessResult(Just<T>)はディクショナリに存在する値に対してのみ呼び出され、キーが見つからない場合は他のオーバーロードが呼び出されることは明らかです。

長所:

  • タイプは仕様となります。
  • ディクショナリには、値型と参照型の両方を含めることができます。

短所:

  • より多くのキーストローク。
  • 対処する複雑さはほとんどありません。
于 2013-01-16T06:56:58.257 に答える
0

私はこのようにすることにしました:

class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set { base[key] = value; }
    }
}

角かっこを使用して、他の辞書と同じように使用できます。これを値型として使用するつもりはないのでTValue、十分な解決策だと思います。

于 2013-01-16T06:11:54.977 に答える