【问题标题】:Encapsulate Dictionary using IDictionary Interface instead of Overriding or Hiding Method使用 IDictionary 接口而不是覆盖或隐藏方法封装字典
【发布时间】:2013-01-07 22:56:06
【问题描述】:

我找不到如何正确封装字典的完整示例。我需要/想要做的就是“覆盖”我知道不能被覆盖的 Add 方法,因为它不是虚拟的。根据一些研究,我发现我需要使用私有 Dictionary 封装它并实现 IDictionary 接口。

我能找到的最完整的示例是here,我主要是复制粘贴并猜测了不匹配的内容(该示例实现了一个只读字典,而我想要具有自定义功能的完整默认功能Add() 方法)。

完整的可编译代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace IDictionary
{
    class Program
    {
        static void Main(string[] args)
        {
            Registers<string, dynamic> DynRegistry = new Registers<string, dynamic>();

            DynRegistry.Add("Foo", 100);
            Console.WriteLine("DynRegistry Size: {0}", DynRegistry.Count);
            foreach (var item in DynRegistry)
            {
                Console.WriteLine("\tName: {0}, Value: {1}", item.Key, item.Value);
            }
            DynRegistry.Add("Foo2", "Hello World");
            Console.WriteLine("DynRegistry Size: {0}", DynRegistry.Count);
            foreach (var item in DynRegistry)
            {
                Console.WriteLine("\tName: {0}, Value: {1}", item.Key, item.Value);
            }
            DynRegistry.Add("Foo", true);
            Console.WriteLine("DynRegistry Size: {0}\r\n", DynRegistry.Count);
            foreach (var item in DynRegistry)
            {
                Console.WriteLine("\tName: {0}, Value: {1}", item.Key, item.Value);
            }
            Console.ReadKey();
        }
    }

    class Registers<TKey, TValue> : IDictionary<TKey, TValue>,  ICollection
    {
        //Fields
        private Dictionary<TKey, TValue> source;
        private object syncRoot;

        //Constructor
                    public Registers()
    {
        this.source = new Dictionary<TKey, TValue>();
    }

        //Wrapped Methods
                                                public void Add(TKey key, TValue value)
    {
        if (this.source.ContainsKey(key))
        {
            this.source[key] = value;
        }
        else
        {
            this.source.Add(key, value);
        }
    }

        //Implement default Interfaces
                        void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        ICollection<KeyValuePair<TKey, TValue>> collection = this.source;
        collection.CopyTo(array, arrayIndex);
    }
        public int Count { get { return this.source.Count; } }
        public ICollection<TKey> Keys { get { return this.source.Keys; } }
        public ICollection<TValue> Values { get { return this.source.Values; } }
        bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly { get { return false; } }
        bool ICollection.IsSynchronized { get { return false; } }
        object ICollection.SyncRoot
    {
        get
        {
            if (this.syncRoot == null)
            {
                ICollection collection = this.source as ICollection;

                if (collection != null)
                {
                    this.syncRoot = collection.SyncRoot;
                }
                else
                {
                    Interlocked.CompareExchange(ref this.syncRoot, new object(), null);
                }
            }
            return this.syncRoot;
        }
    }
        public TValue this[TKey key]
    {
        get { return this.source[key]; }
        set { this.source[key] = value; }
    }
        public bool ContainsKey(TKey key) { return this.source.ContainsKey(key); }
        public bool Remove(TKey key) { return this.source.Remove(key); }
        public bool TryGetValue(TKey key, out TValue value) { return this.source.TryGetValue(key, out value); }
        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        ICollection<KeyValuePair<TKey, TValue>> collection = this.source;
        collection.Add(item);
    }
        void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        ICollection<KeyValuePair<TKey, TValue>> collection = this.source;
        collection.Clear();
    }
        bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
    {
        ICollection<KeyValuePair<TKey, TValue>> collection = this.source;
        return collection.Contains(item);
    }
        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        ICollection<KeyValuePair<TKey, TValue>> collection = this.source;
        return collection.Remove(item);
    }
        void ICollection.CopyTo(Array array, int index)
    {
        ICollection collection = new List<KeyValuePair<TKey, TValue>>(this.source);
        collection.CopyTo(array, index);
    }
        IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        IEnumerable<KeyValuePair<TKey, TValue>> enumerator = this.source;
        return enumerator.GetEnumerator();
    }
        IEnumerator IEnumerable.GetEnumerator()
    {
        return this.source.GetEnumerator();
    }
    }
}

我发布此内容的两个原因:

  1. 因此,需要执行此操作的其他任何人都不必花费 30 分钟重新输入冗余代码。
  2. 有关我是否正确执行此操作的反馈。我对是否/为什么需要实现 ICollection 接口感到困惑(即,普通的 Dictionary 是否会执行此操作,或者 IDictionary 是否会在不需要 ICollection 的情况下拥有完整的 Dictionary 功能补充)。

我真正需要的是一个普通的字典,它有一个 Add 方法,它执行 AddOrReplace() 而不是 Add(或者因为 Key 已经存在而崩溃)。实现这一目标所需的工作似乎有点矫枉过正。

【问题讨论】:

  • 由于您不是从Dictionary&lt;TKey, TValue&gt; 继承的,因此您不需要实现它声明的所有额外接口。只需使用包装内部字典的方法来实现IDictionary&lt;TKey, TValue&gt;。编辑:澄清一下,99% 的情况下,我怀疑您(或您的代码的消费者)会错过不属于 IDictionary&lt;TKey, TValue&gt; 的特定 Dictionary 成员; IDictionary&lt;TKey, TValue&gt; 界面应该为您提供所需的一切。
  • 但是,查看IDictionary&lt;TKey, TValue&gt; 的文档明确表明预期的实现有Add 抛出异常而不是替换/修改现有条目。它似乎打算允许的只是有不同的行为来允许null 与否。考虑到这一点,您的代码的使用者可能会期望 Add 在密钥存在时抛出异常(并且可能取决于此!)而不是修改。如果可能,您应该按照 l4V 的回答遵循标准。见:msdn.microsoft.com/en-us/library/…
  • 我将成为此代码的唯一使用者,它是一次性应用程序。但我确实会使用 I4V 提到的 msdn 标准模式。我没有经常使用字典,所以我不知道它已经这样工作了:/

标签: c# generics dictionary overriding encapsulation


【解决方案1】:

你可以使用

dict[key]=value

add or replace 如果这就是你想要的。所以不需要包装字典。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-01
    • 2013-01-16
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多