سؤال

قبل الأدوية العامة لـ C#، كان الجميع يقومون بترميز المجموعات لكائنات الأعمال الخاصة بهم عن طريق إنشاء قاعدة مجموعة تطبق IEnumerable

أي:

public class CollectionBase : IEnumerable

ومن ثم سيتم استخلاص مجموعات كائنات الأعمال الخاصة بهم من ذلك.

public class BusinessObjectCollection : CollectionBase

الآن مع فئة القائمة العامة، هل يستخدم أي شخص ذلك بدلاً من ذلك؟لقد وجدت أنني أستخدم حلاً وسطًا بين الطريقتين:

public class BusinessObjectCollection : List<BusinessObject>

أفعل هذا لأنني أحب كتابة الأسماء بقوة بدلاً من مجرد تمرير القوائم.

ما هو لك يقترب؟

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

المحلول

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

ومع ذلك، مع ميزة التهيئة المجمعة في الإصدار C# 3.0، هناك بعض المواقف الجديدة التي أود أن أؤيد فيها استخدام فئات التجميع المخصصة.

في الأساس، يسمح C# 3.0 لأي فئة يتم تنفيذها IEnumerable ولديه طريقة إضافة لاستخدام بناء جملة المُهيئ التجميعي الجديد.على سبيل المثال، نظرًا لأن القاموس يحدد طريقة Add(مفتاح K، قيمة V) فمن الممكن تهيئة قاموس باستخدام بناء الجملة هذا:

var d = new Dictionary<string, int>
{
    {"hello", 0},
    {"the answer to life the universe and everything is:", 42}
};

إن الشيء العظيم في هذه الميزة هو أنها تعمل على إضافة طرق مع أي عدد من الوسائط.على سبيل المثال، في ضوء هذه المجموعة:

class c1 : IEnumerable
{
    void Add(int x1, int x2, int x3)
    {
        //...
    }

    //...
}

سيكون من الممكن تهيئته مثل هذا:

var x = new c1
{
    {1,2,3},
    {4,5,6}
}

يمكن أن يكون هذا مفيدًا حقًا إذا كنت بحاجة إلى إنشاء جداول ثابتة للكائنات المعقدة.على سبيل المثال، إذا كنت تستخدم فقط List<Customer> وأردت إنشاء قائمة ثابتة بكائنات العملاء التي يتعين عليك إنشاؤها على النحو التالي:

var x = new List<Customer>
{
    new Customer("Scott Wisniewski", "555-555-5555", "Seattle", "WA"),
    new Customer("John Doe", "555-555-1234", "Los Angeles", "CA"),
    new Customer("Michael Scott", "555-555-8769", "Scranton PA"),
    new Customer("Ali G", "", "Staines", "UK")
}

ومع ذلك، إذا كنت تستخدم مجموعة مخصصة، مثل هذه المجموعة:

class CustomerList  : List<Customer>
{
    public void Add(string name, string phoneNumber, string city, string stateOrCountry)
    {
        Add(new Customer(name, phoneNumber, city, stateOrCounter));
    }
}

يمكنك بعد ذلك تهيئة المجموعة باستخدام بناء الجملة هذا:

var customers = new CustomerList
{
    {"Scott Wisniewski", "555-555-5555", "Seattle", "WA"},
    {"John Doe", "555-555-1234", "Los Angeles", "CA"},
    {"Michael Scott", "555-555-8769", "Scranton PA"},
    {"Ali G", "", "Staines", "UK"}
}

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

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

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

نصائح أخرى

إنه مُستَحسَن أنه في واجهات برمجة التطبيقات العامة لا يجب استخدام القائمة<T>، ولكن لاستخدام المجموعة<T>

إذا كنت ترث منه، فيجب أن تكون بخير يا أفيك.

أفضّل الاستخدام فقط List<BusinessObject>.يؤدي تحديد الكتابة إلى إضافة نموذج معياري غير ضروري إلى الكود. List<BusinessObject> هو نوع محدد، انها ليست مجرد أي List الكائن، لذلك لا يزال مكتوبًا بقوة.

والأهم من ذلك، إعلان شيء ما List<BusinessObject> يجعل من السهل على كل شخص يقرأ الكود معرفة الأنواع التي يتعامل معها، فلا يتعين عليهم البحث فيها لمعرفة ما هي BusinessObjectCollection ثم تذكر أنها مجرد قائمة.من خلال تحديد الكتابة، سيتعين عليك طلب اصطلاح (إعادة) تسمية متسق يجب على الجميع اتباعه حتى يصبح منطقيًا.

استخدم النوع List<BusinessObject> حيث عليك أن تعلن عن قائمة منهم.ومع ذلك ، حيث تقوم بإرجاع قائمة من BusinessObject, ، فكر في العودة IEnumerable<T>, IList<T> أو ReadOnlyCollection<T> - أي.إرجاع أضعف عقد ممكن يرضي العميل.

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

public static int SomeCount(this IEnumerable<BusinessObject> someList)

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

لقد كنت أتحرك ذهابًا وإيابًا بين خيارين:

public class BusinessObjectCollection : List<BusinessObject> {}

أو الطرق التي تقوم فقط بما يلي:

public IEnumerable<BusinessObject> GetBusinessObjects();

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

ربما ينبغي عليك تجنب إنشاء مجموعتك الخاصة لهذا الغرض.من الشائع جدًا الرغبة في تغيير نوع بنية البيانات عدة مرات أثناء إعادة البناء أو عند إضافة ميزات جديدة.من خلال النهج الذي تتبعه، سينتهي بك الأمر بفئة منفصلة لـ BusinessObjectList، وBusinessObjectDictionary، وBusinessObjectTree، وما إلى ذلك.

لا أرى حقًا أي قيمة في إنشاء هذا الفصل لمجرد أن اسم الفصل أكثر قابلية للقراءة.نعم، بناء جملة قوس الزاوية قبيح نوعًا ما، لكنه قياسي في C++ وC# وJava، لذلك حتى إذا لم تكتب كودًا يستخدمه فسوف تصادفه طوال الوقت.

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

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

يمكنك استخدام كليهما.بالنسبة للكسل - أعني الإنتاجية - القائمة هي فئة مفيدة جدًا، وهي أيضًا "شاملة" ومليئة بأعضاء YANGNI بصراحة.إلى جانب الحجة / التوصية المعقولة التي قدمها مقالة MSDN لقد تم ربطي بالفعل بكشف القائمة كعضو عام، وأنا أفضل الطريقة "الثالثة":

أنا شخصياً أستخدم نمط الديكور لعرض ما أحتاجه فقط من القائمة، أي:

public OrderItemCollection : IEnumerable<OrderItem> 
{
    private readonly List<OrderItem> _orderItems = new List<OrderItem>();

    void Add(OrderItem item)
    {
         _orderItems.Add(item)
    }

    //implement only the list members, which are required from your domain. 
    //ie. sum items, calculate weight etc...

    private IEnumerator<string> Enumerator() {
        return _orderItems.GetEnumerator();
    }

    public IEnumerator<string> GetEnumerator() {
        return Enumerator();
    }    
}

علاوة على ذلك، من المحتمل أن أقوم بتجريد OrderItemCollection إلى IOrderItemCollection حتى أتمكن من تبديل تنفيذ IOrderItemCollection في المستقبل (قد أفضّل استخدام كائن داخلي مختلف قابل للتعداد مثل Collection أو المزيد من الأداء لاستخدام مجموعة أو مجموعة زوج القيمة الرئيسية .

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

6 من 1، نصف دزينة من آخر

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

بدون وجود طرق تحميل، تسمح لي إرجاع القائمة بكتابة المزيد من التعليمات البرمجية في فئة عامة شائعة وجعلها تعمل فقط.مثل طريقة التحميل.

وكما أشار شخص آخر، فمن المستحسن عدم الكشف عن القائمة علنًا، وسوف تتذمر شركة FxCop إذا قمت بذلك.يتضمن ذلك الوراثة من القائمة كما في:

public MyTypeCollection : List<MyType>

في معظم الحالات، ستعرض واجهات برمجة التطبيقات العامة IList (أو ICollection أو IEnumerable) حسب الاقتضاء.

في الحالات التي تريد فيها مجموعتك المخصصة، يمكنك إبقاء FxCop هادئًا عن طريق الوراثة من المجموعة بدلاً من القائمة.

إذا اخترت إنشاء فئة المجموعة الخاصة بك، فيجب عليك التحقق من الأنواع الموجودة فيها System.Collections.ObjectModel مساحة الاسم.

تحدد مساحة الاسم الفئات الأساسية الموجودة لتسهيل قيام المنفذين بإنشاء مجموعات مخصصة.

أميل إلى القيام بذلك مع مجموعتي الخاصة إذا كنت أرغب في حماية الوصول إلى القائمة الفعلية.عندما تكتب كائنات أعمال، من المحتمل أنك تحتاج إلى خطاف لمعرفة ما إذا كان سيتم إضافة/إزالة الكائن الخاص بك، وبهذا المعنى أعتقد أن BCollection هي فكرة أفضل.لأنه إذا لم يكن ذلك مطلوبًا، فإن القائمة تكون خفيفة الوزن.قد ترغب أيضًا في التحقق من استخدام IList لتوفير واجهة تجريد إضافية إذا كنت بحاجة إلى نوع من الوكيل (على سبيل المثال.تؤدي المجموعة المزيفة إلى التحميل البطيء من قاعدة البيانات)

لكن...لماذا لا تفكر في Castle ActiveRecord أو أي إطار عمل ORM ناضج آخر؟:)

في معظم الأوقات، أتبع طريقة القائمة ببساطة، لأنها توفر لي جميع الوظائف التي أحتاجها في 90% من الوقت، وعندما تكون هناك حاجة إلى شيء "إضافي"، فإنني أرث منه، وأقوم بتشفير ذلك الجزء الإضافي .

اريد ان افعل هذا:

using BusinessObjectCollection = List<BusinessObject>;

يؤدي هذا فقط إلى إنشاء اسم مستعار بدلاً من نوع جديد تمامًا.أفضل استخدام List<BusinessObject> مباشرة لأنه يترك لي الحرية في تغيير البنية الأساسية للمجموعة في وقت ما في المستقبل دون تغيير الكود الذي يستخدمها (طالما أنني أقدم نفس الخصائص والأساليب).

جرب هذا:

System.Collections.ObjectModel.Collection<BusinessObject>

يجعل من غير الضروري تنفيذ الطريقة الأساسية مثل CollectionBase

هذا هو الطريق:

إرجاع المصفوفات، قبول IEnumerable<T>

=)

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