2011-02-03 19 views
5

Considerare il seguente scenario.polimorfismo, generici e tipi anonimi C#

Documento -> Sezione -> Corpo -> Articoli

documento ha sezioni, una sezione contiene un corpo. Un corpo ha un testo e un elenco di elementi. Gli articoli sono di cosa si tratta. A volte gli elementi sono un elenco di base di stringhe, ma a volte gli elementi contengono un elenco di un tipo di dati personalizzato.

Quindi:

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;} 
    } 

non posso farlo funzionare. La proprietà Items deve essere definita da un tipo per la compilazione. Sono bloccato qui. Posso sistemarlo facilmente creando una classe Section per ognuno dei tipi di sezioni che uso. Ma il fatto è che tutto il resto del codice è lo stesso e tutte le operazioni sulla sezione saranno uguali. L'unica cosa diversa è il tipo di elenco utilizzato nel corpo.

Qual è la migliore pratica per questo. Ho provato generici, astrazioni, ecc. Posso farlo funzionare se si crea la classe Items direttamente dal programma chiamante, ma non riesco a farlo funzionare se Items è dichiarato una proprietà su un'altra classe.

Posso fornire maggiori dettagli se necessario. Grazie ragazzi e ragazze per il vostro supporto.

+0

Forse menzionare tipo anonimo nel titolo è inutile qui ... – digEmAll

+0

Se sectionType è una proprietà sulla classe Sezione, quale impatto ha questo sulla cambiando gli oggetti che sono nel corpo? Hai bisogno di ricrearli? Penso che dovresti rendere le sezioni class generiche. – Kell

+0

C'è una ragione per cui non stai semplicemente creando una classe astratta di oggetti, quindi hai qualcosa come un oggetto String e altri tipi di articoli personalizzati di cui hai bisogno, quindi rappresenti la proprietà Items semplicemente come una lista ? Per me sembra un modo naturale per rappresentare la struttura che stai descrivendo. – SpaceghostAli

risposta

1

Fai un'interfaccia articoli

public interface IItems: IEnumerable, IEnumerator{ 
    } 

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

quindi utilizzare tale ovunque.

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

Questo ha funzionato come un fascino per me. Grazie mille per una risposta così veloce! – Mounhim

+1

Fondamentalmente, è come definire la proprietà 'Items' come' IEnumerable 'o' IEnumerable', Non vedo alcun chiaro vantaggio per usare questo approccio più contorto ... – digEmAll

+0

Bene, per l'esempio banalizzato, no. Ma presumo che nella vita reale abbia in realtà qualche codice di implementazione che rende un oggetto diverso da un oggetto IEnumerable ... –

2

Questa classe non è valido:

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

è necessario definire un tipo concreto qui o fare Body un tipo generico anche. Quindi, o:

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

o:

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

Ovviamente, la seconda opzione richiede di rendere generici anche 'Section' e' Document', e di conseguenza ogni documento sarebbe forzato ad avere lo stesso tipo di elementi. Può essere ragionevole, dipende da che cosa l'OP ha effettivamente bisogno ... – digEmAll

0

L'opzione più ovvia è dichiarare la vostra lista di tipo di oggetto, ma poi bisogna fare i conti con il calo di prestazioni della boxe e unboxing dell'oggetto. Penso che creerei un'interfaccia che definisce il comportamento che stai cercando dall'elemento e assicurati che ogni elemento implementa quell'interfaccia.

Quindi è possibile chiedere ad ogni elemento di fare qualcosa di utile mentre si sta iterando attraverso di essi.

+0

La boxe e la rimozione di unbox si applicano solo ai tipi di valore. Gli elenchi sono generalmente tipi di riferimento. – phoog

0

Questo potrebbe funzionare per voi:

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();} 
    } 
}