2009-03-26 7 views
19

Je serais certain que cette question aborde quelque chose qui aurait été soulevé dans une question précédente, mais je n'ai pas réussi à la trouver.Conversion d'une liste de type de base en une liste de type hérité

Il existe une méthode dans une classe C# qui prend en paramètre une liste générique d'une classe de base. J'ai besoin de passer une liste d'une classe héritée et je ne sais pas exactement comment faire cela. Je reçois une erreur dans mes tentatives. Voici un exemple de code pour illustrer ceci:

public class A 
{ 
    public static void MethodC(List<A>) 
    { 
     // Do Something here with the list 
    } 
} 
public Class B : A 
{ 
    // B inherits from A, A is the Base Class 
} 

// Code utilizing the above method 
List<B> listOfB = new List<B>(); 
A.MethodC((List<A>) listOfB); // Error: this does not work 
A.MethodC(listOfB.ToList<typeof(A)>()); // Error: this does not work 
A.MethodC(listOfB.ConvertAll<A>(typeof(A))); // Error: this does not work 
// how can I accomplish this? It should be possible I would think 

Remarque: Voici ma méthode de travail finale comme référence. J'ai trouvé une solution encore meilleure à mon problème, mais techniquement ce n'était pas une réponse à la question, puisque ma question a été formulée de façon impropre.

public static DataTable 
    ObjectCollectionToDataTable<GLIST> 
     (List<GLIST> ObjectCollection) where GLIST 
       : BaseBusinessObject 
     { 
      DataTable ret = null; 

      if (ObjectCollection != null) 
      { 
       foreach (var b in ObjectCollection) 
       { 

        DataTable dt = b.ToDataTable(); 
        if (ret == null) 
         ret = dt.Clone(); 
        if (dt.Rows.Count > 0) 
         ret.Rows.Add(dt.Rows[0].ItemArray); 
       } 
      } 

      return ret; 
     } 
+0

C'est la même réponse que je vous ai donnée ... –

+0

Et c'est techniquement la réponse à ce que vous avez demandé à l'origine, aussi bien! :) –

Répondre

29

Si vous avez LINQ disponible, vous pouvez faire

var ListOfA = ListOfB.Cast<A>().ToList(); 
+0

Je ne pense pas avoir linq, mais ça a fonctionné quand même. Merci beaucoup pour votre réponse rapide. – stephenbayer

+0

Problème possible - MethodC doit-il modifier la liste pour que ces changements soient visibles en dehors de MethodC? –

+0

Heureux que ça a marché!La seule raison pour laquelle je crois que vous avez les méthodes d'extension LINQ disponibles était l'utilisation de ToList dans votre exemple. –

9

Vous ne pouvez pas faire cela. Pour comprendre pourquoi cela n'est pas autorisé, imaginez ce qui se passerait si Add était appelé sur un List<Derived> après qu'il ait été transtypé en List<Base>. En outre, les réponses impliquant que C# 4.0 sera différent sont erronées. La liste ne sera jamais modifiée pour vous permettre de le faire. Seulement IEnumerable sera - parce qu'il ne permet pas d'éléments à ajouter à la collection.

Mise à jour: La raison pour laquelle cela fonctionne dans la solution que vous avez choisie est parce que vous ne passez plus la même liste. Vous créez une toute nouvelle liste qui est une copie de l'original. C'est pourquoi j'ai demandé de modifier la liste; si MethodC apporte des modifications au nombre d'éléments de la liste, ces modifications seront apportées à une copie et non à la liste d'origine.

Je pense que la solution idéale pour vous est la suivante:

public abstract class A 
{ 
    public void MethodC<TItem>(List<TItem> list) where TItem : A 
    { 
     foreach (var item in list) 
      item.CanBeCalled(); 
    } 

    public abstract void CanBeCalled(); 
} 

public class B : A 
{ 
    public override void CanBeCalled() 
    { 
     Console.WriteLine("Calling into B"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<B> listOfB = new List<B>(); 

     A a = new B(); 

     a.MethodC(listOfB); 
    } 
} 

Remarquez comment, avec cette solution, vous pouvez passer un List<B> directement à MethodC sans avoir besoin de faire cette conversion bizarre là-dessus d'abord. Donc, pas de copie inutile.

La raison pour laquelle cela fonctionne est parce que nous avons dit MethodC pour accepter une liste de tout ce qui est dérivé de A, au lieu d'insister sur le fait qu'il doit être une liste de A.

+0

Je ne pense pas que ce soit vrai, ça marche bien. Mon appel de méthode fait des boucles dans la collection et agit sur les méthodes et propriétés abstraites (override). J'ai utilisé le code ci-dessus dans une réponse précédente, et cela fonctionne très bien. le projet est .NET 2.0 avec CSC.exe (C#) 3.0 en tant que compilateur. – stephenbayer

+0

Voir la mise à jour ci-dessus. –

+0

Je suppose que vous avez du mal à faire fonctionner ça? :) –

3

Voici une réponse qui exclura tous les objets de votre liste du mauvais type. Ceci est un moyen beaucoup plus sûr à mon avis:

List<A> ListOfA = ListOfB.OfType<A>().ToList(); 

La méthode OfType exclut les éléments de la classe dérivée de mal alors que le Cast une erreur.

Questions connexes