2011-02-03 4 views
5

Рассмотрим следующий сценарий.Полиморфизм, дженерики и анонимные типы C#

Документ -> Раздел -> Кузов -> Элементы

Документ имеет секции, секция содержит тело. Тело имеет некоторый текст и список предметов. Вопрос в том, о чем идет речь. Иногда элементы являются основным списком строки, но иногда элементы содержат список пользовательского типа данных.

Итак:

public class Document 
    { 
     public Section[] Sections{get;set;} 
    } 

    public class Section 
    { 
     public SectionType Type{get;set;} 
     public Body {get;set;} 
    } 

    public class Body 
    { 
     //I want the items to be depending on the section type. 
     //If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string 
     public Items<T> Items {get;set;} 
    } 

    public class Items<T>:IEnumerable, IEnumerator 
    { 
    // Do all the plumbing for creating an enumerable collection 
    } 

    public class Experience 
    { 
     public string Prop1{get;set;} 
     public string Prop2 {get;set;} 
    } 

я не могу получить эту работу. Элементы свойства должны быть определены типом для компиляции. Я застрял здесь. Я могу легко это исправить, создав класс Section для каждого из разделов, которые я использую. Но дело в том, что все остальные коды одинаковы, и все операции над секцией будут одинаковыми. Единственное отличие - это тип списка, который используется в теле.

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

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

+0

Может быть, упоминая анонимный тип в названии бесполезно здесь ... – digEmAll

+0

Если sectionType это свойство в классе раздел, какое влияние изменение это оказывает на Элементы, находящиеся в теле? Вам нужно воссоздать их? Я думаю, вы должны сделать класс разделов общим. – Kell

+0

Есть ли причина, по которой вы не просто создаете абстрактный класс элемента, а имеете что-то вроде StringItem и любых других настраиваемых типов элементов, которые вам нужны, а затем представляют свойство Items как просто список ? Для меня это кажется естественным способом представления структуры, которую вы описываете. – SpaceghostAli

ответ

1

сделать интерфейс для элементов

public interface IItems: IEnumerable, IEnumerator{ 
    } 

    public class Items<T>: IItems 
    { 
    // Do all the plumbing for creating an enumerable collection 
    } 

Затем используйте, что и везде.

public class Body 
{ 
    //I want the items to be depending on the section type. 
    //If e.g. the sectiontype is experience, I want the Items to be created with type //Experience. If sectiontype is default I want the Items to be created with type string 
    public IItems Items {get;set;} 
} 
+0

Это работало как прелесть для меня. Большое вам спасибо за такой быстрый ответ! – Mounhim

+1

В принципе, это похоже на определение свойства 'Items' как' IEnumerable 'или' IEnumerable', я не вижу никакого явного преимущества для использования этого более сложного подхода ... – digEmAll

+0

Ну, для тривиализованного примера нет. Но я предполагаю, что в реальной жизни у него действительно есть код реализации, который делает Item отличным от IEnumerable ... –

2

Этого класс не является действительным:

public class Body 
{ 
    public Items<T> Items {get;set;} 
} 

Вам нужно определить конкретный тип здесь или сделать Body общий тип также. Так как:

public class Body<T> 
{ 
    public Items<T> Items {get;set;} 
} 

или:

public class Body 
{ 
    public Items<MyClass> Items {get;set;} 
} 
+0

Очевидно, что второй вариант требует также генерировать «Секцию» и «Документ», и, следовательно, каждый документ будет вынужден иметь один и тот же тип элементов. Это может быть разумным, это зависит от того, что на самом деле требуется OP ... – digEmAll

0

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

public IMyInterface 
{ 
    string dosomething(); 
}  

public Items<IMyInterface> Items {get;set;} 

Тогда вы могли бы попросить каждый элемент сделать что-то полезное, поскольку вы итерации через них.

+0

Бокс и распаковка применяются только к типам значений. Списки обычно являются ссылочными типами. – phoog

0

Это может работать для вас:

public class Document<T> where T: IEnumerable, IEnumerator 
{ 
    private Section<T>[] Sections{get;set;} 
} 

private class Section<T> 
{ 

    private Body<T> body {get;set;} 
} 

private class Body<T> 
{  
    private Items<T> Items {get;set;} 
} 

private class Items<T>:IEnumerable, IEnumerator 
{ 
    // Do all the plumbing for creating an enumerable collection 
    public IEnumerator GetEnumerator() 
    { 
     return (IEnumerator)this; 
    } 
    /* Needed since Implementing IEnumerator*/ 
    public bool MoveNext() 
    {    
     return false; 
    } 
    public void Reset() 
    { 

    } 
    public object Current 
    { 
     get{ return new object();} 
    } 
}