سؤال

أنا أستخدم تسلسل هرمي لفئات المجموعة العامة التي تستمد من فئة قاعدة مجردة لتخزين عناصر الكيان التي تستمد أيضا من فئة قاعدة مجردة:

abstract class ItemBase { }

class MyItem : ItemBase
{
    public MyItem()
    {
    }
}


abstract class CollectionBase<T> : Collection<T> where T : ItemBase, new() { }

class MyCollection : CollectionBase<MyItem> { }

أهداف هذا النموذج هي إنفاذ الانضباط الصارم من النوع على أعضاء أي فئة مشتقة من CollectionBaseu003CT> ولضمان أن يكون هؤلاء الأعضاء منشئ عام افتراضي. حتى الآن يعمل.

الآن أريد إنشاء طريقة المصنع التي ترجع مثيل فئة مشتقة من CollectionBaseu003CT> وبعد أنا أفهم أن النهج المعتاد سيكون:

public CollectionBase<T> CreateCollection<T>();

... أو ربما ...

public T Create CreateCollection<T>();

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

public CollectionBase<> CreateCollection();

أفترض أن هذا آخر من مشكلات التباين العام الشائكة، ولكن حتى بعد قراءة تفسير إريك ليببيرت في هذا الموضوع، ما زلت غير واضح ما إذا كان ما أحاول القيام به من المحتمل أن يكون ممكنا في C # 4.0، وما إذا كان هناك بسيط الحل البديل في C # 3.0.

ويرجع الفضل في ذلك مسبقا لأفكارك.

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

المحلول

دعنا نقول أن طريقة المصنع كانت خلق عنصر واحد. سيكون لديك:

public ItemBase CreateItem();

يجب عليك استخدام ItemBase لأنه لا يمكنك معرفة أي شيء أكثر تحديدا. تطبيق هذا المبدأ في طريقة التجميع، تحصل على:

public CollectionBase<ItemBase> CreateCollection();

بسبب عدم وجود التباين، تحتاج إلى فئة محول تستمد من CollectionBase<ItemBase> ويلف على المجموعة الفعلية التي يتم إنشاؤها.

في C # 4.0 يمكنك فقط إرجاع المجموعة الفعلية.

يحرر: قد يبدو المصنع مثل هذا، مع محول مضمن:

public class CollectionFactory
{
    public CollectionBase<ItemBase> CreateCollection()
    {
        if(someCondition)
        {
            return CreateAdapter(new MyCollection());
        }
        else
        {
            return CreateAdapter(new MyOtherCollection());
        }
    }

    private static CollectionAdapter<T> CreateAdapter<T>(CollectionBase<T> collection) where T : ItemBase, new()
    {
        return new CollectionAdapter<T>(collection);
    }

    private class CollectionAdapter<T> : CollectionBase<ItemBase> where T : ItemBase, new()
    {
        private CollectionBase<T> _collection;

        internal CollectionAdapter(CollectionBase<T> collection)
        {
            _collection = collection;
        }

        // Implement CollectionBase API by passing through to _collection
    }
}

نصائح أخرى

ربما ما تحتاجه هو:

public CollectionBase<Object> CreateCollection();

لأن كل فئة يرث مباشرة أو غير مباشر من فئة الكائنات.

لم أفعل ذلك في الواقع، والاعتذار إذا كان ذلك بالكامل ساذج، ولكن ...

public CollectionBase<Object> CreateCollection();

?

إذا كنت تريد حقا أن تكون أي شيء، فيمكنك فقط إرجاع icollection، ثم يمكن للمستهلكين الاتصال .Cast<ItemBase>() طريقة التمديد كما يحتاجون.

من ما أفهمه، في .NET 4.0، ستتمكن من العودة CollectionBase<ItemBase>, ، لكنني لم أحاول ذلك على بيتا حتى الآن.

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