جمع<T> مقابل قائمة<T> ما ينبغي أن تستخدم على واجهات?

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

سؤال

يبدو أدناه:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

عند تشغيل التعليمات البرمجية تحليل أحصل على التوصية التالية.

تحذير 3 CA1002 :مايكروسوفت.التصميم :تغيير 'قائمة' في 'IMyClass.GetList()' استخدام جمع ReadOnlyCollection أو KeyedCollection

كيف يمكنني إصلاح هذا وما هو ممارسة جيدة هنا ؟

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

المحلول

الإجابة عن "لماذا" جزء من السؤال لماذا لا List<T>, الأسباب هي المستقبل التدقيق و API البساطة.

التدقيق المستقبل

List<T> لم يتم تصميم للمد بسهولة من قبل subclassing ؛ وهي مصممة لتكون سريعة على تطبيقات داخلي.ستلاحظ الأساليب على أنها ليست افتراضية و لذلك لا يمكن تجاوزها و لا توجد كلاب في Add/Insert/Remove عمليات.

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

وذلك من خلال العودة إما إلى الدرجة التي يمكن أن تكون بسهولة ثم subclassed مثل Collection<T> أو واجهة مثل IList<T>, ICollection<T> أو IEnumerable<T> يمكنك تغيير إعدادات الداخلية تنفيذ مجموعة مختلفة النوع لتلبية الاحتياجات الخاصة بك دون كسر رمز من المستهلكين لأنه يمكن أن يكون لا يزال عاد كنوع كانوا يتوقعون.

API البساطة

List<T> يحتوي على الكثير من العمليات المفيدة مثل BinarySearch, Sort وهلم جرا.ومع ذلك إذا كان هذا هو جمع يتم تعريض فمن المحتمل أن يمكنك التحكم دلالات القائمة ، وليس المستهلكين.حتى حين صفك داخليا قد تحتاج هذه العمليات فمن المستبعد جدا أن المستهلكين من فئة ترغب (أو حتى) ندعو لهم.

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

نصائح أخرى

وأود أن أعلن شخصيا أن يعود واجهة بدلا من جمع ملموسة. إذا كنت تريد حقا قائمة الوصول، استخدم IList<T> . خلاف ذلك، والنظر في ICollection<T> و <لأ href = "HTTP: // MSDN .microsoft.com / EN-US / مكتبة / 9eekhta0.aspx "يختلط =" noreferrer "> IEnumerable<T> .

ولقد معظمها حول التلخيص تطبيقات الخاصة بك بعيدا بدلا من تعريض الكائن قائمة لمعالجته بشكل مباشر.

وانها ليست ممارسة جيدة للسماح غيرها من الأشياء (أو أشخاص) تعديل حالة الأشياء الخاصة بك مباشرة. أعتقد حاصل الملكية / اضعي.

كوكتيل -> للجمع العادي
ReadOnlyCollection -> بالنسبة للمجموعات التي لا ينبغي تعديلها
KeyedCollection -> عندما تريد القواميس بدلا

وكيفية إصلاح ذلك يعتمد على ما تريد صفك القيام به، والغرض من طريقة GetList (). يمكنك وضع؟

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

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

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

إذا كان لديك مجموعة والعامة، مثلا:

public int[] MyIntegers { get; }

وكنت أعتقد لأنه لا يوجد سوى "الحصول على" استرجاع أن لا أحد يمكن أن الفوضى مع القيم، ولكن هذا ليس صحيحا. يمكن لأي شخص أن تغيير القيم داخل هناك مثل هذا:

someObject.MyIngegers[3] = 12345;

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

وشيء للإضافة على الرغم من أنه قد تم منذ وقت طويل منذ هذا سئل.

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

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

وأنا لا أرى أي مشكلة مع عودة شيء من هذا القبيل

this.InternalData.Filter(crteria).ToList();

إذا عدت إلى قطع <م> نسخة من البيانات الداخلية، أو نتيجة فصل استعلام البيانات - أستطيع العودة بأمان List<TItem> من دون الكشف عن أي تفاصيل التنفيذ، والسماح لاستخدام البيانات التي تم إرجاعها في مريحة الطريق.

ولكن هذا يعتمد على نوع من المستهلكين وأتوقع - إذا كان هذا هو شيء من هذا القبيل شبكة البيانات أنا أفضل أن يعود IEnumerable<TItem> <م> الذي سيكون قائمة نسخ من العناصر على أي حال في معظم الحالات:)

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

وأعتقد أن عليك أن لا تقلق بشأن ذلك، ولكن إذا كنت تريد حقا لإرضاء أداة تحليل رمز، فقط تفعل ما يلي:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top