2010-02-09 32 views
6

¿Es posible "upcast" de una clase genérica basada en T, en una clase genérica basada en algo más general que T?Upcasting con un parámetro de tipo genérico

Por ejemplo, supongo que tengo una clase llamada Derived que hereda de una clase llamada Base. ¿Puedo volver a hacer algo como esto:

List<Derived> der = new List<Derived>(); 
List<Base> bas = (List<Base>) der; 

O bien, el uso de interfaces, es que siempre que sea posible hacer algo como esto:

List<MyClonableType> specific = new List<MyClonableType>(); 
List<IClonable> general = (List<IClonable>)specific; 

Como está escrito aquí, cada uno de estos ejemplos falla con un InvalidCastException. La pregunta sobre la que estamos discutiendo es si es realmente imposible, o simplemente un error de sintaxis que podría corregirse si supiéramos cómo.

+0

Java tiene '' para este tipo de construcción, Me sorprendería que C# no tenga un equivalente. – Romain

+1

C# tiene restricciones genéricas (la palabra clave where) para lo mismo que extends, pero I ' No estoy seguro de que eso es lo que busca Auraseer. Él quiere usar la varianza en la colección por lo que parece. –

+0

@Romain, ese molde no es válido en C#, pero puede definir un método como 'nulo Proceso (Lista lista) donde T: Base {...}' – finnw

Respuesta

3

C# 4.0 will have that feature.

Será habilitado en las interfaces y los delegados que se adhieren a ciertas reglas. List<T> no será compatible, ya que es una clase concreta. IList<T> tampoco será compatible, ya que sus métodos usan T en las posiciones in y out.

+0

Ese enlace también me dice con certeza que este lanzamiento no está permitido antes de 4.0. Eso es exactamente lo que quería saber. – Auraseer

+0

Incluso en .NET 4.0 no se aplicará a la lista . – kvb

+0

Buen punto. La varianza solo se admite en interfaces y delegados. –

0

No es agradable extensión de LINQ:

der.ToList<Base>(); 
+1

Creo que este método crea una colección completamente nueva. Puede ser útil, suponiendo que tienes a Linq, pero no es lo mismo que un elenco. – Auraseer

+0

Es cierto que puede tratar específicamente con tipos IEnumberable de esta manera, pero no es un modelo real, ya que la pregunta es. En este caso, el método ToList () crea una nueva lista de y la rellena lanzando cada elemento desde el original. –

+0

Si solo va a * leer * la lista (que es el único caso en el que el reparto tendría sentido), presumiblemente no importa si está leyendo una copia o el original. – finnw

1

Este

List<Derived> der = new List<Derived>(); 
List<Base> bas = (List<Base>)der; 

no es posible y nunca debería ser posible. Qué sucede aquí:

Base b = new Base(); 
bas.Add(b); 

Kaboom! es lo que sucede Si lo anterior fuera legal bas solo se referiría a der y der no se pueden agregar instancias de Base que es lo que el Add estaría tratando de hacer. (Para ser concretos, piensa en Base como Animal y Derived como Cat, no se puede emitir un List<Cat> a un List<Animal> porque entonces se podría añadir una instancia de Dog a la lista fundido, que fallaría porque es realmente un List<Cat>.)

Por razones similares

List<MyClonableType> specific = new List<MyClonableType>(); 
List<IClonable> general = (List<IClonable>)specific; 

nunca debería ser posible.

En C# 4.0 algunos de estos problemas se resolverán con la noción de covariance and contravariance. Por ejemplo, en C# 4.0 que esto sea legal:

List<Derived> der = new List<Derived>(); 
IEnumerable<Base> bas = der; 

Esto se debe a IEnumerable<Base> solamente escupe casos de Base y desde todos los Derived s son Base s que esto está bien. Dicho de otra manera, IEnumerable<Base> dice "Sé cómo lanzar instancias de Base a ti", mientras que List<Derived> dice "Sé cómo presentar instancias de Derived a ti."Pero como todos Derived s son Base s, esto significa que List<Derived> también sabe cómo lanzar instancias de Base a usted. Por lo tanto, debe poder asignarse a una instancia de IEnumerable<Base>. Esto es lo que es posible en C# 4.0. es un ejemplo de covarianza.

debo subrayar que para tipos como List<T> que tienen métodos que ambos comen T s y escupir T es que no es posible.

Cuestiones relacionadas