2011-02-03 36 views
5

Tenga en cuenta la situación siguiente.polimorfismo, genéricos y tipos anónimos C#

Documento -> Sección -> Cuerpo -> Los productos que

documento tiene secciones, una sección contiene un cuerpo. Un cuerpo tiene texto y una lista de elementos. Los ítems son de lo que se trata la pregunta. A veces, los elementos son una lista básica de cadenas, pero a veces los elementos contienen una lista de un tipo de datos personalizado.

Así:

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

no puedo conseguir que esto funcione. La propiedad Artículos tiene que estar definida por un tipo para compilar. Estoy atrapado aquí. Puedo arreglar esto fácilmente creando una clase de sección para cada tipo de sección que uso. Pero el problema es que el resto del código es el mismo y todas las operaciones en la sección serán las mismas. Lo único diferente es el tipo de lista utilizada en el Cuerpo.

¿Cuál es la mejor práctica para esto. He intentado con genéricos, abstracción, etc. Puedo hacer que funcione si creo la clase Elementos directamente desde el programa de llamada, pero no puedo hacer que funcione si se declara una propiedad en otra clase.

Puedo proporcionar más detalles si es necesario. Gracias chicos y chicas por vuestro apoyo.

+0

Quizá mencionar tipo anónimo en el título es inútil aquí ... – digEmAll

+0

Si sectionType es una propiedad de la clase de la sección, ¿qué impacto tiene esto sobre cambiando los elementos que están en el cuerpo? ¿Necesitas recrearlos? Creo que deberías hacer que las secciones sean genéricas. – Kell

+0

¿Hay alguna razón por la que no solo esté haciendo una clase abstracta de Artículo y luego tenga algo así como un StringItem y cualquier otro tipo de Artículo personalizado que necesite y luego represente su propiedad Artículos simplemente como una Lista ? Para mí, eso parece una forma natural de representar la estructura que describes. – SpaceghostAli

Respuesta

1

Hacer una interfaz para artículos

public interface IItems: IEnumerable, IEnumerator{ 
    } 

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

A continuación, utilice que en cualquier otro lugar.

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

Esto funcionó como un encanto para mí. ¡Muchas gracias por una respuesta tan rápida! – Mounhim

+1

Básicamente, es como definir la propiedad 'Items' como' IEnumerable 'o' IEnumerable', no veo ninguna ventaja clara para usar este enfoque más complicado ... – digEmAll

+0

Bueno, para el ejemplo trivializado, no. Pero supongo que en la vida real tiene un código de implementación que hace que un elemento sea diferente de un IEnumerable ... –

2

Esta clase no es válido:

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

es necesario definir un tipo concreto aquí o hacer Body un tipo genérico también. Así que o bien:

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

o:

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

Obviamente, la segunda opción requiere hacer genéricos también 'Sección' y' Documento', y consecuentemente cada documento se verá forzado a tener el mismo tipo de elementos. Puede ser razonable, depende de lo que realmente necesite el OP ... – digEmAll

0

La opción más obvia es declarar su lista de tipo de objeto, pero entonces usted tiene que lidiar con el impacto en el rendimiento del boxeo y unboxing del objeto. Creo que crearía una interfaz que defina el comportamiento que está buscando desde el elemento y asegúrese de que cada elemento implemente esa interfaz.

public IMyInterface 
{ 
    string dosomething(); 
}  

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

Luego, puede pedirle a cada elemento que haga algo útil mientras itera a través de ellos.

+0

El boxeo y el desempaquetado solo se aplican a los tipos de valores. Las listas son generalmente tipos de referencia. – phoog

0

Esto podría funcionar para usted:

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