2009-02-11 30 views
5

Tengo un IList<DerivedClass> que quiero convertir a ICollection<BaseClass> pero cuando intento un lanzamiento explícito, obtengo null. ¿Es posible hacer esto sin crear y completar una nueva colección?Lanzando una colección genérica al tipo base

Editar: Ya que sólo quiero leer de la colección, que me pasa a utilizar un método genérico:

public void PopulateList<BaseClass>(ICollection<T> collection) 

entonces puedo pasarle un IList<DerivedClass>. ¿Hay una buena manera de almacenar en caché esta lista para que pueda actualizarla cuando sea necesario? Mi primera inclinación es usar:

Object cachedCollection; 
Type cachedType; 
public void PopulateList<BaseClass>(ICollection<T> collection) { 
    cachedCollection = collection; 
    cachedType = T; 

    // other stuff... 
} 

private void Refresh() { 
    PopulateList<cachedType>(cachedCollection as ICollection<cachedType>); 
} 

¿Alguien tiene una mejor manera de hacer esto?

+0

Una muestra de código sería muy útil. Sin eso, es difícil darle algo como una respuesta útil. –

Respuesta

8

La respuesta corta es "No." Debería crear una nueva colección con el nuevo tipo de BaseClass y completarla.

Si lo piensas bien, tiene sentido. Si pudieras simplemente "lanzar" tu colección a BaseClass, podrías pegar en ella algo que era del tipo "BaseClass", forzando así a un objeto BaseClass simple a una Colección DerivedClass. Esto sería contrario al propósito de crear una Colección con Type-Safety.

En el caso extremo, si tenía dos clases derivadas, Foo y Bar, podría forzar los objetos Bar en una colección de objetos Foo volviendo a escribir la colección en una colección de BaseClass.

+0

Eso tiene sentido.Solo leo de la colección, así que no estaba pensando en las implicaciones completas de lo que quería hacer. – dmo

+0

var baseCollection = (ICollection) derivedList.CastToList (); –

3

No creo que sea posible, y de hecho no debería ser:

class BaseClass {} 
class DerivedClass : BaseClass {} 
class OtherClass : BaseClass {} 

void test() 
{ 
    List<DerivedClass> list = new List<DerivedClass>(); 
    slice(list); //you want to do this 
} 

void slice(IList<BaseClass> list) 
{ 
    //yikes! adding OtherClass to List<DerivedClass> 
    list.Add(new OtherClass()); 
} 
+1

En .NET 4.0, esta situación se resuelve mediante el uso de las palabras clave "in" y "out". –

2

El cambio entre los contenedores genéricos de las clases derivadas y clases base no es compatible. (Funciona con matrices) Es posible escribir un convertidor de tipo para realizar el cambio de forma razonablemente limpia sin copiar elementos manualmente entre las listas.

Salida este enlace para una descripción de la emisión/limitación y una solución: http://www.25hoursaday.com/weblog/CommentView.aspx?guid=AF7AA888-A227-454C-8687-71FA77186064

En el fondo es una buena versión genérica habilitado.

+0

Sí, ConvertAll es tu amigo aquí :) –

6

Esto se denomina covarianza y aunque actualmente no es compatible con genéricos en .net, se agregará en el marco 4.0 (junto con el opuesto que es contra-varianza).

Este excelente video del PDC 2008 es sesión sobre C# futuros dada por Anders Hejlsberg:

http://channel9.msdn.com/pdc2008/TL16/

+0

Gracias por la información, Jim. Echaré un vistazo a eso. – dmo

2

Si .NET 3.5 es una opción, puede utilizar el método Cast<T> extensión en System.Core.dll para obtener una lectura -sólo IEnumerable<T> para la colección:

using System.Linq; 
... 
private void Refresh() { 
    PopulateList(cachedCollection.Cast<cachedType>()); 
} 
0

puede convertir cada elemento en un nuevo iterador:

var collectionOfBase = (collectionOfDerived as IEnumerable).Cast<BaseClass>(); 
Cuestiones relacionadas