سؤال

انا لدي ICollection<T> مُسَمًّى foos في صفي الذي أريد أن أعرضه للقراءة فقط (انظر هذا السؤال).أرى أن الواجهة تحدد خاصية .IsReadOnly, ، وهو ما يبدو مناسبا...سؤالي هو هذا:كيف يمكنني توضيح ذلك للمستهلك من الفصل foos للقراءة فقط؟

لا أريد الاعتماد عليهم في تذكر الاستعلام .IsReadOnly قبل تجربة طريقة غير منفذة مثل .Add().من الناحية المثالية، أود أن فضح foos ك ReadOnlyCollection<T>, ، لكنه لا ينفذ IList<T>.هل يجب أن أفضح foo عبر طريقة تسمى، على سبيل المثال، GetReadOnlyFooCollection وليس عن طريق الممتلكات؟إذا كان الأمر كذلك، ألا يربك هذا الشخص الذي يتوقع بعد ذلك أ ReadOnlyCollection<T>?

هذا هو الإصدار C# 2.0، لذا فإن طرق الامتداد مثل ToList() غير متوفرة...

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

المحلول

يبدو أنني استقرت على إرجاع IEnumerable مع الكائنات المستنسخة.

public IEnumerable<Foose> GetFooseList() {
   foreach(var foos in Collection) {
     yield return foos.Clone();
   }
}
  • يتطلب طريقة استنساخ على Foos.

وهذا لا يسمح بأي تغييرات في المجموعة.تذكر أن ReadonlyCollection "متسرب" حيث يمكن تغيير الكائنات الموجودة بداخله كما هو مذكور في رابط في منشور آخر.

نصائح أخرى

ويمكنك جعل "فوس" لReadOnlyCollection مثل هذا:

ReadOnlyCollection<T> readOnlyCollection = foos.ToList<T>().AsReadOnly();

وبعد ذلك يمكنك تعريضها كخاصية من صفك.

وتحرير:

    class FooContainer
    {
        private ICollection<Foo> foos;
        public ReadOnlyCollection<Foo> ReadOnlyFoos { get { return foos.ToList<Foo>().AsReadOnly();} }

    }

ملحوظة: يجب أن نتذكر أنه بمجرد أن تحصل على جمع ReadOnlyFoos لم يعد "متزامنة" مع ICollection فوس الخاص بك. انظر الخيط الذي أشرت إليه .

منذ كتابة السؤال، أضاف .NET 4.0 ملف IReadOnlyCollection<T> واجهه المستخدم؛ربما يكون من الجيد استخدام ذلك كنوع الإرجاع المعلن.

ومع ذلك، فإن هذا يترك السؤال مفتوحًا حول أي نوع من مثال لكي ترجع.قد يكون أحد الأساليب هو استنساخ كافة العناصر الموجودة في المجموعة الأصلية.قد يكون الخيار الآخر هو إرجاع غلاف للقراءة فقط دائمًا.والثالث هو إعادة المجموعة الأصلية إذا تم تنفيذها IReadOnlyCollection<T>.سيكون كل نهج هو الأفضل في سياقات معينة، ولكنه سيكون أقل من المثالي (أو ربما مروعًا تمامًا) في سياقات أخرى.لسوء الحظ، لا توفر Microsoft أي وسيلة قياسية يمكن من خلالها طرح سؤالين مهمين للغاية:

  1. هل تعد بأن تحتوي دائمًا وإلى الأبد على نفس العناصر التي تفعلها الآن؟

  2. هل يمكن أن تتعرض بأمان مباشرة إلى التعليمات البرمجية التي ليس من المفترض أن تعدل محتوياتك؟

يعتمد نمط التغليف المناسب على ما يتوقع رمز العميل فعله بالشيء الذي يتلقاه.بعض السيناريوهات التي يجب تجنبها:

  1. تم توفير كائن من النوع الذي يمكن للعميل التعرف عليه على أنه غير قابل للتغيير، ولكن بدلاً من إعادته مباشرة، يتم تكراره، باستخدام نوع لا يتعرف عليه العميل على أنه غير قابل للتغيير.وبالتالي، يضطر العميل إلى تكرار المجموعة مرة أخرى.

  2. تم توفير كائن من النوع الذي يمكن للعميل التعرف عليه على أنه غير قابل للتغيير، ولكن قبل إعادته يتم تغليفه بطريقة لا يستطيع العميل معرفة ما إذا كانت المجموعة غير قابلة للتغيير أم لا، وبالتالي يضطر إلى التكرار.

  3. يتم توفير كائن من النوع القابل للتغيير والذي ليس من المفترض أن يتم تحويله بواسطة العميل (يتم إرساله إلى واجهة للقراءة فقط).ثم يتم عرضه مباشرة لعميل آخر يحدد أنه نوع قابل للتغيير ويشرع في تعديله.

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

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

أتمنى أن تضيف ميكروسوفت وسيلة قياسية يمكن من خلالها طرح الأسئلة المذكورة أعلاه على المجموعات، أو، الأفضل من ذلك، أن يُطلب منها إنتاج لقطة ثابتة لحالتها الحالية.يمكن لمجموعة غير قابلة للتغيير أن تُرجع لقطة غير قابلة للتغيير لحالتها الحالية بسعر رخيص جدًا (فقط تُرجع نفسها) وحتى بعض أنواع المجموعات القابلة للتغيير يمكن أن تُرجع لقطة غير قابلة للتغيير بتكلفة أقل بكثير من تكلفة التعداد الكامل (على سبيل المثال.أ List<T> قد يكون مدعوما من قبل اثنين T[][] المصفوفات، إحداها تحتوي على مراجع إلى مصفوفات غير قابلة للمشاركة مكونة من 256 عنصرًا، والأخرى تحتوي على مراجع إلى مصفوفات قابلة للتغيير غير قابلة للمشاركة مكونة من 256 عنصرًا.يتطلب عمل لقطة للقائمة استنساخ المصفوفات الداخلية التي تحتوي على العناصر التي تم تعديلها منذ اللقطة الأخيرة فقط، وهو ما قد يكون أرخص بكثير من استنساخ القائمة بأكملها.لسوء الحظ، نظرًا لعدم وجود واجهة قياسية "لإنشاء لقطة غير قابلة للتغيير" [لاحظ ذلك ICloneable لا يتم احتسابه، نظرًا لأن استنساخ القائمة القابلة للتغيير سيكون قابلاً للتغيير؛بينما يمكن للمرء عمل لقطة غير قابلة للتغيير عن طريق تغليف نسخة قابلة للتغيير في غلاف للقراءة فقط، فإن ذلك لن يعمل إلا مع الأشياء القابلة للاستنساخ، وحتى الأنواع غير القابلة للاستنساخ يجب أن تظل تدعم وظيفة "لقطة قابلة للتغيير".]

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

وأنا عادة إرجاع IEnumerable<T>.

وبمجرد إجراء مجموعة للقراءة فقط (لذلك أساليب مثل Add، Remove وClear لم تعد تعمل) هناك لم يبق الكثير أن جمع يدعم أن enumerable لا - فقط Count وContains، وأعتقد

إذا المستهلكين من الطبقة الخاصة بك حقا بحاجة لعلاج مثل عناصر انهم في مجموعة، فإنه من السهل بما فيه الكفاية لتمرير IEnumerable إلى منشئ List<T> ل.

وإرجاع T []:

private ICollection<T> items;

public T[] Items
{
    get { return new List<T>(items).ToArray(); }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top