كيفية منع المتصل الأسلوب من تعديل المجموعة التي تم إرجاعها؟[ينسخ]

StackOverflow https://stackoverflow.com/questions/1219268

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

لدي طرق لإعادة المجموعات الخاصة إلى المتصل وأريد منع المتصل من تعديل المجموعات التي تم إرجاعها.

private readonly Foo[] foos;

public IEnumerable<Foo> GetFoos()
{
    return this.foos;
}

في الوقت الحالي، المجموعة الخاصة عبارة عن مصفوفة ثابتة، ولكن في المستقبل قد تصبح المجموعة قائمة إذا ظهرت الحاجة إلى إضافة عناصر جديدة في وقت التشغيل.

هناك عدة حلول لمنع المتصل من تعديل المجموعة.عودة IEnumerable<T> هو الحل الأبسط، ولكن لا يزال بإمكان المتصل رفع قيمة الإرجاع إلى IList<T> وتعديل المجموعة.

((IList<Foo>)GetFoos())[0] = otherFoo;

إن استنساخ المجموعات له عيب واضح وهو أن هناك مجموعتين يمكن أن تتطورا بشكل مستقل.لقد نظرت حتى الآن في الخيارات التالية.

  1. التفاف المجموعة في ReadOnlyCollection<T>.
  2. إرجاع أحد مكررات LINQ المحددة بواسطة Enumerable الفصل عن طريق إجراء إسقاط وهمي مثل list.Select(item => item).في الواقع أنا أفكر في استخدام Where(item => true) لأن المكرر الذي تم إرجاعه يبدو أكثر خفة الوزن.
  3. كتابة غلاف مخصص.

ما لا أحبه في الاستخدام ReadOnlyCollection<T> هو أنه ينفذ IList<T> والاتصال Add() أو الوصول إلى المفهرس سوف يسبب استثناءات.في حين أن هذا صحيح تمامًا من الناحية النظرية، إلا أنه لا يوجد تقريبًا أي عمليات فحص حقيقية للكود IList<T>.IsReadOnly أو IList<T>.IsFixedSize.

باستخدام مكررات LINQ - قمت بتغليف الكود بطريقة الامتداد MakeReadOnly() - يمنع هذا السيناريو، ولكن له طعم الاختراق.

كتابة غلاف مخصص؟إعادة اختراع العجلة؟

أي أفكار أو اعتبارات أو حلول أخرى؟


أثناء وضع علامة على هذا السؤال، اكتشفت هذا السؤال Stack Overflow لم ألاحظ من قبل.يقترح جون سكيت استخدام "LINQ hack" أيضًا، ولكن باستخدام أكثر كفاءة Skip(0).

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

المحلول

لسوء الحظ لا توجد وسيلة لتحقيقه بالضبط ما الذي تبحث عنه في الإصدار الحالي من الإطار.إنه ببساطة ليس لديه مفهوم لمجموعة غير قابلة للتغيير / للقراءة فقط قابلة للفهرسة على كل من النوع الملموس ونمط الواجهة.

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

أنت فقط خيارك الحقيقي هو أن...

  • تحديد فئة المجموعة الخاصة بك
  • إما تنفيذ فقط IEnumerable<T> أو تحديد واجهة الحاجة للقراءة فقط والتي تنفذها مجموعتك.

نصائح أخرى

ماذا عن عمل نسخة عميقة من الكائن الذي يتم إرجاعه؟[لذلك لن يكون هناك أي تأثير على المجموعة الأصلية حتى لو قرر المتصل إجراء تغييرات على النسخة المعادة]

القائمة والمصفوفة لهما طريقة AsReadOnly :

public IEnumerable<Foo> GetFoos()
{
    return Array.AsReadOnly(this.foos);
    // or if it is a List<T>
    // return this.foos.AsReadOnly();
}

في مثل هذه الحالات، أقوم بإنشاء طرق داخل الفصل للوصول إلى العناصر الفردية للمجموعة الخاصة.يمكنك أيضًا تحقيق المفهرس (http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx) في الفصل الذي يحتوي على مجموعة خاصة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top