2012-10-10 76 views
5

tengo clase base para mis entidadesCrear una lista de medicamentos genéricos

public class Entity<T> where T : Entity<T>, new() 
{ 
    public XElement ToXElement() 
    { 
    } 
    public static T FromXElement(XElement x) 
    { 
    } 
} 

tengo que usar esta extraña construcción Entity<T> where T : Entity<T>, porque quiero FromXElement método estático a ser de tipo fuerte Además, tengo algunas entidades, como que

public class Category : Entity<Category> 
{ 
} 
public class Collection : Entity<Collection> 
{ 
} 

¿Cómo puedo crear una lista genérica de mis entidades, utilizando la clase base?

var list = new List<Entity<?>>(); 
list.Add(new Category()); 
list.Add(new Collection()); 
+0

¿Qué estás tratando de lograr? ¿Por qué necesitas esos tipos dispares en una colección? –

+0

Y la categoría y la colección de clases ¿son tipos genéricos de ... ellos mismos? –

+1

@DanielPersson se llama el [patrón de plantilla curiosamente se repite] (http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx) –

Respuesta

4

No se puede con esa definición. No existe una "clase base común" entre Category y Collection (que no sea object, por supuesto).

Si hay eran, dicen que si Entity<T> se definieron como:

public class Entity 
{ 
} 

public class Entity<T> : Entity where T : Entity<T>, new() 
{ 
    public XElement ToXElement() 
    { 
    } 
    public static T FromXElement(XElement x) 
    { 
    } 
} 

entonces usted podría hacer

var list = new List<Entity>(); 
list.Add(new Category()); 
list.Add(new Collection()); 

Pero ¿qué haría que usted comprar?

+0

necesito FromXElement/ToXElement en la clase base. Ésto no encajar – Evgraf

+0

@Evgraf - entonces usted tendrá que emitir. No hay un método 'FromXElement' que implementen tanto' Category' como 'Collection' (ya que tienen diferentes tipos de devolución). –

0

Se puede definir una clase no genérica a ser la clase base de todas las clases de entidad

public class Entity 
{ 
} 

y hacer Entidad heredan Entidad

public class Entity<T> : Entity where T : Entity<T>, new() 
{ 
} 

Ahora se puede crear la lista de entidades como :

var list = new List<Entity>(); 
0

puede resolver este p roblem mediante la adición de una versión no genérica de la clase

class Entity 
{ 
    // methods 

    public T As<T>() 
    { 
    if (this is T) return (T)this; 
    throw new InvalidCastException(); 
    } 
} 

class Entity<T> : Entity where T : Entity<T>, new() 

class Cathegory : Entity<T> {} 

y luego crear la lista de la clase base:

var list = new List<Entity>() 
list.Add(new Cathegory()); 

Entonces, si usted desea llamar una operación de "genérico específico", se necesita llamar a la función "As" o simplemente lanzar el objeto.

1

crear una interfaz de marcador:

public interface IAmAGenericEntity { } 

public class Entity<T> where T : IAmAGenericEntity, new() 
// ... 

public class Category : Entity<T>, IAmAGenericEntity 
// .... 

var list = new List<IAmAGenericEntity>(); 
// ... 
1

De la falta de un marcador en abstractEntity, supongo que To/FromXElement uso reflexión y debería funcionar para cualquier subtipo de Entity. Le recomiendo que estructurar sus clases de la siguiente manera:

public class Entity 
{ 
    public XElement ToXElement() { ... } 

    protected static T FromXElement<T>(XElement x) 
     where T : Entity 
    { 
     ... 
    } 
} 

public class Category : Entity 
{ 
    public static Category : FromXElement(XElement x) 
    { 
     return FromXElement<Category>(x); 
    } 
} 

El "repetitivo" es mínima, y ​​que no requiere que creativa eludir el sistema de tipos. No tiene que preocuparse por la falta de una base común o de conversiones manuales.Si lo desea, puede eliminar el texto modelo del todo y simplemente la construcción de los objetos directamente de Entity:

public class Entity 
{ 
    public XElement ToXElement() { ... } 

    public static T FromXElement<T>(XElement x) 
     where T : Entity 
    { 
     ... 
    } 
} 

En esencia, lo que está haciendo es implementar un tipo de clase, que no soporta directamente la C#. Hay una serie de formas de solucionar esta falta, pero por lo general encontrar a ser más problemas de lo que vale la pena, sobre todo cuando se trata de métodos estáticos. Si C# soportara métodos de extensión estáticos, sería simple, pero lamentablemente no es así.

Cuestiones relacionadas