2014-09-21 3 views
0

Говорят, что у меня есть ряд классов:List <> конкретных типов классов

abstract class MyClass { } 
class MyFirstClass : MyClass { } 
class MySecondClass : MyClass { } 
class MyThirdClass : MyClass { } 

Я хочу сделать что-то на основе настраиваемого списка этих производных типов классов, поэтому я хочу, чтобы сохранить выбранный класс Type s в списке. Я знаю, что могу создать List<Type>, но теоретически могу добавить класс в этот список. С другой стороны, List<MyClass> будет списком экземпляров этих классов, а не списком самих типов. Я мог бы также создать enum с одним значением, соответствующим каждому производному типу, и иметь фабричный метод для создания правильного по мере необходимости, но это, по крайней мере, еще два места, которые я должен был бы обновить, когда добавлю MyFourthClass.

Есть ли способ сделать что-то вроде new List<typeof(MyClass)>() = new[] { typeof(MyFirstClass), typeof(MyThirdClass)}? Является ли тот факт, что я задаю этот вопрос, подразумевает проблему с моим дизайном?

+0

Вы можете работать с «списком » и при необходимости набрасывать на производные типы. Было бы полезно узнать больше о ваш вариант использования, поскольку может быть лучший дизайн. –

+2

Если вы после решения, в соответствии с которым компилятор сможет ограничить ваш список только производными от MyClass типов, я не думаю, что возможно. Конечно, вы можете реализовать собственный список , который отклоняет недопустимые типы во время выполнения. – lesscode

+1

@TyCobb: Я думаю, что OP хочет список экземпляров System.Type, а не экземпляры MyClass – lesscode

ответ

2

Что вы хотите - это общий список типов (List<Type>), но, как вы сказали, вы можете вставить туда любой тип. Решение, которое я могу дать вам реализовать свой собственный список типов из MyClass, например:

class TypeMyClassList : IList<Type> 
{ 
    private readonly List<Type> _list = new List<Type>(); 

    private bool CheckType(Type type) 
    { 
     return type.IsSubclassOf(typeof (MyClass)) || typeof (MyClass) == type; 
    } 

    public IEnumerator<Type> GetEnumerator() 
    { 
     return _list.GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    public void Add(Type item) 
    { 
     if (CheckType(item)) 
      _list.Add(item); 
     else 
      throw new InvalidOperationException("You can't add other types than derived from A"); 
    } 

    public void Clear() 
    { 
     _list.Clear(); 
    } 

    public bool Contains(Type item) 
    { 
     return _list.Contains(item); 
    } 

    public void CopyTo(Type[] array, int arrayIndex) 
    { 
     _list.CopyTo(array, arrayIndex); 
    } 

    public bool Remove(Type item) 
    { 
     return _list.Remove(item); 
    } 

    public int Count 
    { 
     get { return _list.Count; } 
    } 

    public bool IsReadOnly { get { return false; } } 

    public int IndexOf(Type item) 
    { 
     return _list.IndexOf(item); 
    } 

    public void Insert(int index, Type item) 
    { 
     if (!CheckType(item)) 
      throw new InvalidOperationException("You can't insert other types than derived from A"); 
     _list.Add(item); 
    } 

    public void RemoveAt(int index) 
    { 
     _list.RemoveAt(index); 
    } 

    public Type this[int index] 
    { 
     get 
     { 
      return _list[index]; 
     } 
     set 
     { 
      Insert(index, value); 
     } 
    } 
} 

Тогда вы могли бы сделать так думает, что вы хотите:

var typeMyClassList = new TypeMyClassList 
     { 
      typeof(MyClass), 
      typeof(MyClassA), 
      typeof(MyClassB) 
     }; 

Плохо то, что он будет позволяет сделать это в compilance времени (ошибка будет поднята во время выполнения):

var typeMyClassList = new TypeMyClassList 
     { 
      typeof(MyClass), 
      typeof(MyClassA), 
      typeof(MyClassB), 
      typeof(string) 
     }; 
+0

Я думаю это сложнее, чем я готов использовать в этом сценарии, но это будет * то, что я буду использовать, если буду идти вперед. Пора передумать. Благодаря! – Bobson

1

Там нет никакого способа сделать это со статической, во время компиляции проверки типов. Лучше всего пойти с таким решением, как Raul Otaño, в котором вы делаете свои проверки во время выполнения.

Почему вы не можете это сделать? Причина в том, что в C# отсутствуют статические типы метакласса. Метакласс - это класс класса. Другими словами, экземпляры метакласса сами являются классами. Если C# было метаклассами, вы могли бы сказать что-то вроде IList<MyClassMeta> (или, возможно, синтаксис будет IList<meta MyClass> и компилятор только позволит вам пройти MyClass (или его подклассов) в качестве «экземпляров», например,

IList<meta MyClass> list; 
list.Add(MyClass); 

Я вы давно не пользовались этой функциональностью, но я не ожидаю этого в ближайшее время.

+1

Спасибо за объяснение! – Bobson

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