2011-01-27 1 views
0

Допустим у меня есть следующие классы, которые имеют различные варианты реализации, основанную на объекте должны храниться в:параметров типа, ограничение и ковариационные/контравариации

public class ListOfPersistent<T> : 
    IList<T> where T : Persistent {... implementation ...} 

public class ListOfNonPersistent<T> : 
    IList<T> {... implementation ...} 

И я хочу, чтобы использовать одну из другой версии на вышеизложенном классы делать что-то вроде этого:

public class PersistentList<T> : IList<T> { 
    protected PersistentList() { 
    if (list != null) { 
     return; 
    } 

    if (Extensions.IsPersistent<T>()) { 
     list = new ListOfPersistent<T>(); 

    } else { 
     list = new ListOfNonPersistent<T>(); 
    } 
    } 

    protected IList<T> list; 
    .... 
} 

конечно выше не компилируется, потому что есть тип ограничивают на первый класс, и ни на секунду. Есть ли способ, которым я могу: Скажите компилятору, что он не должен проверять ограничение в этом конкретном случае (list = new ListOfPersistent<T>()), потому что я ЗНАЮ, что он будет такого типа, или сделать некоторую магию ковариации/контравариантности, поэтому код компилируется без каких-либо проблем?

ответ

1

Ковариация и контравариантность здесь не помогут, потому что IList<T> является инвариантным.

Лично я бы сказал, что у вас есть недостаток в дизайне вашего класса. Вы не должны создавать экземпляр ListOfPersistent<T>, а затем помещать его в переменную, тип которой IList<T>, несовместим. К сожалению, я не могу предложить хорошую альтернативу, потому что я понятия не имею, как вы планируете использовать эти классы или какова ваша общая цель; но я могу сделать рекомендации с оговоркой, что это Hacky и, вероятно, следует использовать только, если вы действительно знаете, что вы делаете:

public static class ListUtils 
{ 
    public static object CreateListOfPersistent(Type elementType) 
    { 
     if (!typeof(Persistent).IsAssignableFrom(elementType)) 
      throw new ArgumentException("elementType must derive from Persistent.", "elementType"); 
     var listType = typeof(ListOfPersistent<>).MakeGenericType(elementType); 
     return Activator.CreateInstance(listType); 
    } 
} 

// ... 

if (Extensions.IsPersistent<T>()) 
    list = (IList<T>) ListUtils.CreateListOfPersistent(typeof(T)); 
else 
    list = new ListOfNonPersistent<T>(); 
+0

Эти два класса делают то же самое, но так как внутреннее работа совершенно другая, и один из них зависит от типа, который должен быть постоянным, поэтому есть два класса. Конечно, я могу поместить много, если ... на один из классов, но это будет сложно поддерживать и не очень быстро. В основном, PersistentList - это только декоратор, так как он не имеет каких-либо функциональных возможностей, просто используйте подчеркнутую функциональность IList, что опять же, в зависимости от того, является ли тип T стойким или нет, требуется две разные реализации. – CheloXL

+0

@CheloXL: Как я уже сказал, трудно дать вам какие-либо советы о том, как реализовать вещи, не зная, что вы на самом деле пытаетесь сделать. Вы только говорите мне, как вы пытаетесь его реализовать. В общем, когда я нахожусь в ситуации, когда мне нужно отдельное поведение для двух разных типов объектов, я создаю иерархию классов с виртуальными (или абстрактными) методами и добавляю разную функциональность в те, а не в специализированный контейнерный класс, - но Я не могу сказать, применимо ли это в вашем конкретном сценарии. – Timwi

+0

Я выполняю менеджер сохранения объектов. Класс Persistent является базовым классом для всех постоянных объектов, но нет необходимости наследовать этот класс, чтобы сделать объект постоянным. Разница в том, что класс, который наследует Persistent, будет сохранен как ссылка (ссылка) на класс, а класс, который не наследует Persistent, будет сохранен как-есть (поэтому, если объект Persistent, у вас будет только один объект obj и несколько ссылок, если obj не является стойким, у вас будет несколько копий одного и того же класса). Вот почему две реализации разные. – CheloXL

Смежные вопросы