3

指定されたキーを持つ KVP がない場合に、dic["nonexistentKey"]try-catch で通常をラップせずにデフォルト値を返すように、辞書の動作を変更するにはどうすればよいですか?

4

4 に答える 4

6

をカプセル化Dictionary<TKey,TValue>、 を実装する独自のクラスを作成できますIDictionary<TKey,TValue>

これは辞書のように動作しますが、存在しないキーを任意の方法で処理する動作を記述できます。

Dictionary<TKey,TValue>ただし、実際のクラスの機能を変更することはできません。

于 2012-10-30T16:17:47.987 に答える
5

必要に応じて、拡張メソッドを IDictionary または Dictionary に追加することもできます。

public static class IDictionaryExtensions
{
    public static TValue ValueAtOrDefault<TKey, TValue>(
        this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
    {
        if (dictionary == null || !dictionary.ContainsKey(key))
        {
            return defaultValue;
        }

        return dictionary[key];
    }
}

ArgumentNullException例のようにデフォルト値を返すのではなく、ディクショナリが nullの場合にスローしたい場合があることに注意してください...あなたに適したものは何でも。

于 2012-10-30T16:19:26.973 に答える
3

Dictionary.TryGetValueを使用します。

Dictionary<int, YourType> dictionary = ...;
YourType x;
if (!dictionary.TryGetValue(123, out x))
{
    x = new YourType();
}

// here X will be assigned to the value or the default if the key was not present.

デフォルトのアプローチを本当にオーバーライドする必要がある場合はdictionary[key]、このクラスを (辞書自体として、または既存の辞書のラッパーとして) 使用できます。

/// <summary>
/// A dictionary implementation that returns the default value of <typeparamref name="TValue"/> when the key is not present in the dictionary.
/// </summary>
public class DictionaryWithDefaults<TKey, TValue> : IDictionary<TKey, TValue>
{
    /// <summary>
    /// Holds the actual data using standard dictionary.
    /// </summary>
    private IDictionary<TKey, TValue> _storage;

    /// <summary>
    /// Initializes a new instance of the <see cref="DictionaryWithDefaults{TValue}" /> class.
    /// The data is stored directly in this dictionary.
    /// </summary>
    public DictionaryWithDefaults()
    {
        this._storage = new Dictionary<TKey, TValue>();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DictionaryWithDefaults{TValue}" /> class.
    /// This dictionary acts as a wrapper for the data stored in the dictionary <paramref name="forWrapping" />.
    /// </summary>
    /// <param name="forWrapping">The dictionary object for wrapping.</param>
    /// <exception cref="System.ArgumentNullException">when <paramref name="forWrapping"/> is <c>null</c></exception>
    public DictionaryWithDefaults(IDictionary<TKey, TValue> forWrapping)
    {
        if (forWrapping == null)
            throw new ArgumentNullException("forWrapping");

        this._storage = forWrapping;
    }

    public void Add(TKey key, TValue value)
    {
        this._storage.Add(key, value);
    }

    public bool ContainsKey(TKey key)
    {
        return this._storage.ContainsKey(key);
    }

    public ICollection<TKey> Keys
    {
        get { return this._storage.Keys; }
    }

    public bool Remove(TKey key)
    {
        return this._storage.Remove(key);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        // always return a value, even if the key does not exist.
        // this is also the only place one would modify if the default value has to be customized (passed in the constructor etc.)
        if (!this._storage.TryGetValue(key, out value))
            value = default(TValue);

        return true;
    }

    public ICollection<TValue> Values
    {
        get { return this._storage.Values; }
    }

    public TValue this[TKey key]
    {
        get
        {
            TValue value;
            this.TryGetValue(key, out value);
            return value;
        }
        set
        {
            this._storage[key] = value;
        }
    }

    public void Add(KeyValuePair<TKey, TValue> item)
    {
        this._storage.Add(item);
    }

    public void Clear()
    {
        this._storage.Clear();
    }

    public bool Contains(KeyValuePair<TKey, TValue> item)
    {
        return this._storage.Contains(item);
    }

    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        this._storage.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return this._storage.Count; }
    }

    public bool IsReadOnly
    {
        get { return this._storage.IsReadOnly; }
    }

    public bool Remove(KeyValuePair<TKey, TValue> item)
    {
        return this._storage.Remove(item);
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return this._storage.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this._storage.GetEnumerator();
    }
}
于 2012-10-30T16:22:27.670 に答える
1

いいえ、包む必要があります。this[]は仮想メソッドではないため、オーバーライドできません。

したがって、最善の策は、公開(または選択されたメソッドのみ)し、try/catchIDictionaryでラップする単純なクラスを作成することです。this[] get

于 2012-10-30T16:19:04.503 に答える