سؤال

وصفي تحتوي على Dictionary<T, S> dict، وأريد أن فضح ReadOnlyCollection<T> المفاتيح. كيف يمكنني القيام بذلك دون نسخ Dictionary<T, S>.KeyCollection dict.Keys إلى مجموعة ومن ثم تعريض مجموعة باعتباره ReadOnlyCollection؟

وأريد ReadOnlyCollection ليكون المجمع الصحيح، أي. لتعكس التغيرات في قاموس الكامنة، وكما أفهمها نسخ مجموعة إلى مجموعة لن تفعل هذا (وكذلك على ما يبدو غير فعال - لا أريد في الواقع مجموعة جديدة، فقط لفضح جمع الكامن وراء مفاتيح .. .). ومن شأن أي أفكار محل تقدير كبير!

وتحرير: أنا باستخدام C # 2.0، لذلك لم يكن لديك طرق الإرشاد مثل .ToList (بسهولة) المتاحة.

هل كانت مفيدة؟

المحلول

إذا كنت تريد حقا أن استخدام ReadOnlyCollection ، والمسألة هي أن منشئ ReadOnlyCollection يأخذ IList ، في حين أن KeyCollection من قاموس ليست سوى ICollection .

وحتى إذا كنت تريد التفاف KeyCollection في ReadOnlyCollection، سيكون لديك لإنشاء محول (أو المجمع) اكتب وتنفيذ IList ، التفاف KeyCollection. لذلك سيبدو:

var dictionary = ...;
var readonly_keys = new ReadOnlyCollection<T> (new CollectionListWrapper<T> (dictionary.Keys)
);

وليس أنيقة جدا على الرغم من خاصة أن KeyCollection بالفعل مجموعة للقراءة فقط، والتي يمكن أن تمر ببساطة حولها باعتبارها ICollection :)

نصائح أخرى

وقال DrJokepu أنه قد يكون من الصعب تنفيذ مجمع للمفاتيح مجموعة. ولكن، في هذه الحالة بالذات، وأعتقد أن التنفيذ يست صعبة للغاية، لأنه كما نعلم، هذا هو مجمع للقراءة فقط.

وهذا يسمح لنا أن نتجاهل بعض الأساليب التي، في حالة أخرى، سيكون من الصعب تنفيذها.

وفيما يلي التنفيذ السريع للمجمع لDictionary.KeyCollection:

class MyListWrapper<T, TValue> : IList<T>
{
    private Dictionary<T, TValue>.KeyCollection keys;

    public MyListWrapper(Dictionary<T, TValue>.KeyCollection keys)
    {
        this.keys = keys;
    }

    #region IList<T> Members

    public int IndexOf(T item)
    {
        if (item == null)
            throw new ArgumentNullException();
        IEnumerator<T> e = keys.GetEnumerator();
        int i = 0;
        while (e.MoveNext())
        {
            if (e.Current.Equals(item))
                return i;
            i++;
        }
        throw new Exception("Item not found!");
    }

    public void Insert(int index, T item)
    {
        throw new NotImplementedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotImplementedException();
    }

    public T this[int index]
    {
        get
        {
            IEnumerator<T> e = keys.GetEnumerator();
            if (index < 0 || index > keys.Count)
                throw new IndexOutOfRangeException();
            int i = 0;
            while (e.MoveNext() && i != index)
            {
                i++;
            }
            return e.Current;
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    #endregion

    #region ICollection<T> Members

    public void Add(T item)
    {
        throw new NotImplementedException();
    }

    public void Clear()
    {
        throw new NotImplementedException();
    }

    public bool Contains(T item)
    {
        return keys.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        keys.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return keys.Count; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public bool Remove(T item)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        return keys.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return keys.GetEnumerator();
    }

    #endregion
}

وهذا قد لا يكون أفضل تنفيذ لهذه الأساليب :) ولكنه كان فقط لإثبات أن هذا يمكن القيام به.

وعلى افتراض انك تستخدم C # 3.0 و لديك:

وقاموس د؛

ثم

وReadOnlyCollection ص = جديد ReadOnlyCollection (d.Keys.ToList ())؛

وسوف تحتاج أيضا إلى استيراد مساحة الاسم System.Linq.

ولسوء الحظ لا يمكنك لهذا direcly بقدر ما أعرف كما KeyCollection<T> لا يعرض أي شيء من شأنه أن يسمح لك أن تفعل ذلك بسهولة.

هل يمكن، مع ذلك، فئة فرعية ReadOnlyCollection<T> بحيث يتلقى المنشئ الخاص به القاموس نفسه وتجاوز الأساليب المناسبة بحيث يعرض العناصر في قاموس كما لو كانوا بنودها الخاصة.

لسجل، في. NET 4.6، وKeyCollection<T> تنفذ IReadOnlyCollection<T>، حتى إذا كنت تستخدم تلك الواجهة، لا يزال بإمكانك تعكس التغيرات إلى القاموس، لا يزال الحصول على O (1) يحتوي على، ولأن واجهة التغاير، يمكنك عودة IReadOnlyCollection<some base type>

وانها قبيحة، ولكن هذا سوف نفعل ذلك

Dictionary<int,string> dict = new Dictionary<int, string>();
...
ReadOnlyCollection<int> roc = new ReadOnlyCollection<int>((new List<int>((IEnumerable<int>)dict.Keys)));
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top