2009-02-11 7 views
5

J'ai un IList<DerivedClass> que je veux convertir en ICollection<BaseClass> mais quand je tente une distribution explicite, j'obtiens null. Est-il possible de le faire sans créer et remplir une nouvelle collection?Lance une collection générique vers le type de base

Edit: Puisque je veux seulement lire de la collection, je suis passé à l'aide d'une méthode générique:

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

Ensuite, je peux passer un IList<DerivedClass>. Est-il un bon moyen de mettre en cache cette liste afin que je puisse l'actualiser quand j'en ai besoin. Mon premier penchant est d'utiliser:

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

Quelqu'un at-il une meilleure façon de le faire?

+0

Un exemple de code serait très utile. Sans cela, il est difficile de vous donner quelque chose comme une réponse utile. –

Répondre

8

La réponse courte est "Non". Vous devez créer une nouvelle collection avec le nouveau type BaseClass et la remplir.

Si vous y pensez, c'est logique. Si vous pouviez simplement "convertir" votre collection en BaseClass, vous pourriez alors y coller quelque chose de type "BaseClass", forçant ainsi un simple Objet BaseClass dans une Collection DerivedClass. Cela irait à l'encontre de l'objectif de créer une collection avec type de sécurité. Dans le cas extrême, si vous possédiez deux classes dérivées, Foo et Bar, vous pourriez forcer des objets Bar dans une collection d'objets Foo en renvoyant la collection vers une collection de BaseClass.

+0

Cela a du sens.Je lis seulement de la collection, donc je ne pensais pas à toutes les implications de ce que je voulais faire. – dmo

+0

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

3

Je ne pense pas qu'il soit possible, et en effet il ne faut pas:

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

Dans .NET 4.0, cette situation est résolue grâce à l'utilisation des mots clés "in" et "out". –

2

Commutation entre les conteneurs génériques des classes dérivées et les classes de base n'est pas pris en charge. (Il fonctionne avec les tableaux) Il est possible d'écrire un convertisseur de type pour exécuter correctement le commutateur sans copier manuellement les éléments entre les listes.

Consultez ce lien pour obtenir une description du problème/limitation et une solution: http://www.25hoursaday.com/weblog/CommentView.aspx?guid=AF7AA888-A227-454C-8687-71FA77186064

vers le bas au fond est une belle version générique compatible.

+0

Oui, ConvertAll est votre ami ici :) –

6

Ceci est appelé covariance et bien qu'il ne soit pas actuellement supporté avec des génériques dans .net, il sera ajouté dans le framework 4.0 (avec le contraire qui est la contra-variance).

Cette excellente vidéo de PDC 2008 est session sur les contrats à terme C# donnée par Anders Hejlsberg:

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

+0

Merci pour l'info, Jim. Je vais jeter un coup d'oeil à ça. – dmo

2

Si .NET 3.5 est une option, vous pouvez utiliser la méthode d'extension Cast<T> à System.Core.dll pour obtenir une lecture -Seulement IEnumerable<T> de la collection:

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

Vous pouvez lancer chaque élément dans le nouveau iterator:

var collectionOfBase = (collectionOfDerived as IEnumerable).Cast<BaseClass>(); 
Questions connexes