2011-06-06 64 views
15

我需要知道如何重寫特定靜態類中某個Dictionary的Add方法。有什麼建議麼?Override Dictionary.Add

如果它的事項,該詞典是這樣的:

public static Dictionary<MyEnum,MyArray[]> 

有什麼建議?

+3

它不是一個靜態的類,但靜態字段。 – 2011-06-06 10:33:59

+2

你爲什麼要公開'Dictionary'對象而不是通用接口? – 2011-06-06 10:36:21

+0

我其實不知道。我只是在鬼混和學習新的方式,並意識到我不知道如何覆蓋添加方法。這不適用於生產代碼。 – Phil 2011-06-06 10:38:50

回答

31

因爲它不是虛擬的,所以不能覆蓋方法Dictionary<,>。您可以通過在派生類中添加具有相同名稱/簽名的方法來隱藏它,但隱藏與重寫不同。如果有人投給基礎班,他仍會撥打錯誤的Add

正確的方法做,這是創建自己的類,它實現IDictionary<,>(界面),但一個Dictionary<,>(類),而不是一個Dictionary<,>

class MyDictionary<TKey,TValue>:IDictionary<TKey,TValue> 
{ 
    private Dictionary<TKey,TValue> backingDictionary; 

    //Implement the interface here 
    //Delegating most of the logic to your backingDictionary 
    ... 
} 
2

實際上使用「new」關鍵字更簡單。當我的對象包含他們自己獨特的ID值時,我經常這樣做。

// Warning Air Code - Subject to bonehead mistakes 

internal class SomeDict : Dictionary<myKeyType, myObjectType> 
{ 
    public new void Add(myKeyType key, myObjectType value) 
    { 
     this.Add(value); 
    } 

    internal void Add(myObjectType value) 
    { 
     base.Add(value.Id, value); 
    } 

} 
+7

這是隱藏,而不是壓倒一切。最好使''密封'。如果某人從'SomeDict'繼承,那麼你認爲他們會得到哪個'Add'方法?當有人做這個功能時會發生什麼:(mySomeDict as Dictionary ).Add(k,o)?哪一個叫?隱藏通常不會導致維護噩夢 - 封裝(如接受的答案所示)遠不那麼危險。 – ctacke 2012-03-31 23:07:05

7

我使用CodesInChaos的解決方案。由於在執行IDictionary<TKey, TValue>時涉及到一些開銷,所以這是一個用於一般消費的虛擬實現。我在下面包含一些評論和一個例子,以供選擇閱讀。讓我知道我是否應該修復或改進一些東西。我沒有做太多的測試,但它似乎可以覆蓋add方法。

using System.Collections; 
using System.Collections.Generic; 

/// <summary> 
/// Represents a collection of keys and values. This is an abstract base-class wrapping a <see cref="T:System.Collections.Generic.Dictionary`2"/> with 
/// virtual method that can be overridden. This class can be used to override the default functionality of <see cref="T:System.Collections.Generic.Dictionary`2"/>. 
/// </summary> 
/// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam> 
/// <typeparam name="TValue">The type of the values in the dictionary.</typeparam> 
public class VirtualDictionary<TKey, TValue> : IDictionary<TKey, TValue> 
{ 
    protected IDictionary<TKey, TValue> wrappedDictionary; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that is empty, has the default initial capacity, and uses the default equality comparer for the key type. 
    /// </summary> 
    public VirtualDictionary() 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(); 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that is empty, has the specified initial capacity, and uses the default equality comparer for the key type. 
    /// </summary> 
    /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.VirtualDictionary`2"/> can contain.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception> 
    public VirtualDictionary(int capacity) 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(capacity); 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that is empty, has the default initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>. 
    /// </summary> 
    /// <param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param> 
    public VirtualDictionary(IEqualityComparer<TKey> comparer) 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(comparer); 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that is empty, has the specified initial capacity, and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>. 
    /// </summary> 
    /// <param name="capacity">The initial number of elements that the <see cref="VirtualDictionary{TKey,TValue}"/> can contain.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception> 
    public VirtualDictionary(int capacity, IEqualityComparer<TKey> comparer) 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(capacity, comparer); 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the default equality comparer for the key type. 
    /// </summary> 
    /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="VirtualDictionary{TKey,TValue}"/>.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception> 
    public VirtualDictionary(IDictionary<TKey, TValue> dictionary) 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(dictionary); 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="VirtualDictionary{TKey,TValue}"/> class that contains elements copied from the specified <see cref="T:System.Collections.Generic.IDictionary`2"/> and uses the specified <see cref="T:System.Collections.Generic.IEqualityComparer`1"/>. 
    /// </summary> 
    /// <param name="dictionary">The <see cref="T:System.Collections.Generic.IDictionary`2"/> whose elements are copied to the new <see cref="VirtualDictionary{TKey,TValue}"/>.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IEqualityComparer`1"/> implementation to use when comparing keys, or null to use the default <see cref="T:System.Collections.Generic.EqualityComparer`1"/> for the type of the key.</param><exception cref="T:System.ArgumentNullException"><paramref name="dictionary"/> is null.</exception><exception cref="T:System.ArgumentException"><paramref name="dictionary"/> contains one or more duplicate keys.</exception> 
    public VirtualDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) 
    { 
     wrappedDictionary = new Dictionary<TKey, TValue>(dictionary, comparer); 
    } 

    /// <summary> 
    /// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </summary> 
    /// <param name="key">The object to use as the key of the element to add.</param><param name="value">The object to use as the value of the element to add.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.ArgumentException">An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
    public virtual void Add(TKey key, TValue value) 
    { 
     wrappedDictionary.Add(key, value); 
    } 

    /// <summary> 
    /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key. 
    /// </summary> 
    /// <returns> 
    /// true if the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the key; otherwise, false. 
    /// </returns> 
    /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception> 
    public virtual bool ContainsKey(TKey key) 
    { 
     return wrappedDictionary.ContainsKey(key); 
    } 

    /// <summary> 
    /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </returns> 
    public virtual ICollection<TKey> Keys 
    { 
     get 
     { 
      return wrappedDictionary.Keys; 
     } 
    } 

    /// <summary> 
    /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </summary> 
    /// <returns> 
    /// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </returns> 
    /// <param name="key">The key of the element to remove.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
    public virtual bool Remove(TKey key) 
    { 
     return wrappedDictionary.Remove(key); 
    } 

    /// <summary> 
    /// Gets the value associated with the specified key. 
    /// </summary> 
    /// <returns> 
    /// true if the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key; otherwise, false. 
    /// </returns> 
    /// <param name="key">The key whose value to get.</param><param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception> 
    public virtual bool TryGetValue(TKey key, out TValue value) 
    { 
     return wrappedDictionary.TryGetValue(key, out value); 
    } 

    /// <summary> 
    /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
    /// </returns> 
    public virtual ICollection<TValue> Values 
    { 
     get 
     { 
      return wrappedDictionary.Values; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the element with the specified key. 
    /// </summary> 
    /// <returns> 
    /// The element with the specified key. 
    /// </returns> 
    /// <param name="key">The key of the element to get or set.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.Collections.Generic.KeyNotFoundException">The property is retrieved and <paramref name="key"/> is not found.</exception><exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
    public virtual TValue this[TKey key] 
    { 
     get 
     { 
      return wrappedDictionary[key]; 
     } 
     set 
     { 
      wrappedDictionary[key] = value; 
     } 
    } 

    /// <summary> 
    /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> 
    public virtual void Add(KeyValuePair<TKey, TValue> item) 
    { 
     wrappedDictionary.Add(item); 
    } 

    /// <summary> 
    /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception> 
    public virtual void Clear() 
    { 
     wrappedDictionary.Clear(); 
    } 

    /// <summary> 
    /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value. 
    /// </summary> 
    /// <returns> 
    /// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. 
    /// </returns> 
    /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param> 
    public virtual bool Contains(KeyValuePair<TKey, TValue> item) 
    { 
     return wrappedDictionary.Contains(item); 
    } 

    /// <summary> 
    /// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index. 
    /// </summary> 
    /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</exception> 
    public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
    { 
     wrappedDictionary.CopyTo(array, arrayIndex); 
    } 

    /// <summary> 
    /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <returns> 
    /// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </returns> 
    public virtual int Count 
    { 
     get 
     { 
      return wrappedDictionary.Count; 
     } 
    } 

    /// <summary> 
    /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. 
    /// </summary> 
    /// <returns> 
    /// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false. 
    /// </returns> 
    public virtual bool IsReadOnly 
    { 
     get { return wrappedDictionary.IsReadOnly; } 
    } 

    /// <summary> 
    /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <returns> 
    /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </returns> 
    /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> 
    public virtual bool Remove(KeyValuePair<TKey, TValue> item) 
    { 
     return wrappedDictionary.Remove(item); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through the collection. 
    /// </summary> 
    /// <returns> 
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>1</filterpriority> 
    public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
    { 
     return wrappedDictionary.GetEnumerator(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through a collection. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>2</filterpriority> 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

我的用例是能夠運行相同的代碼來操作DataTable和作爲IDictionary的kendo數據源結果。所以,我用自定義IDictionary包裝了DataTable,以便在DataRow上對IDictionary進行更新。也許有人會覺得有用,應該作爲一個示例實現。

public class DataRowDictionaryWrapper : VirtualDictionary<string, object> 
{ 
    private DataRow row; 

    public DataRowDictionaryWrapper(DataRow row) 
    { 
     this.row = row; 
     this.wrappedDictionary = row.Table.Columns.Cast<DataColumn>().ToDictionary(key => key.ColumnName, c => row[c]); 
    } 

    public override void Add(string key, object value) 
    { 
     DataColumn col = row.Table.Columns[key]; 
     if (col == null) 
     { 
      col = new DataColumn(key); 
      row.Table.Columns.Add(col); 
     } 
     row[col] = value; 

     base[key] = value; 
    } 
} 

public class DataTableDictionaryWrapper : IEnumerable<IDictionary<string, object>> 
{ 
    private DataTable dt; 

    public DataTableDictionaryWrapper(DataTable dt) 
    { 
     this.dt = dt; 
    } 

    public IEnumerator<IDictionary<string, object>> GetEnumerator() 
    { 
     foreach (DataRow row in dt.Rows) 
     { 
      yield return new DataRowDictionaryWrapper(row); 
     } 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return this.GetEnumerator(); 
    } 
} 
+0

你新的'Add'實現並不實際調用基本的'Add'方法。它正在調用那個微妙不同的二傳手。然而,如果給定的鍵存在,添加應該失敗,但是你不會。最好調用'base.Addkey,value);'而不是。 – 2017-01-07 20:39:28

0

另一種「快速和骯髒的」修復

如果你需要一些額外的邏輯添加到Add方法,你可以創建你自己的方法,以稍微不同的簽名,並在代碼中使用。

public class MyOwnDictionary<TKey, TValue>: Dictionary<TKey, TValue> 
{ 
    public void AddPlus(TKey key, TValue value) 
    { 
     //some custom logic here 

     base.Add(key,value); 
    } 
} 

(但是這可能會導致維護困難)