2009-03-03 6 views
1

je le code suivantListe <T> algorithmes de coulée et des considérations de performance

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

      var aObj = new A(); 

      aObj.Go(aList.Cast<IB>()); 
     } 
    } 

    class A : IB 
    { 
     public void Go(IEnumerable<IB> interfaceList) 
     { 
      foreach (IB ibby in interfaceList) 
      { 
       Console.WriteLine("Here"); 
      } 
     } 
    } 

    interface IB 
    { 
     void Go(IEnumerable<IB> interfaceList); 
    } 

}

J'ai essayé d'abord passer une liste mais doesn't work. Après beaucoup d'aide de SO j'ai trouvé que passer IEnumerable est le seul moyen de faire passer les objets comme .ofType (IB).

Malheureusement pour moi, dans mon code la ligne suivante sera exécuté des milliers de fois:

aList.Cast<IB>(); 

Je me demandais si quelqu'un savait comment il a été mis en œuvre algorithmiquement (en IL) et que son ordre de temps est. C'est-à-dire, est-ce plus rapide qu'une boucle foreach qui jette juste chaque élément, ou est-ce exactement ce qu'il fait?

EDIT La classe principale doit gérer une liste des objets réels. Mais le lecteur est seulement autorisé à les toucher à travers l'interface.

Répondre

10

Vous devez changer Go à:

public void Go<T>(IEnumerable<T> interfaceList) 
    where T : IB 
{ 
    foreach (IB ibby in interfaceList) 
    { 
     Console.WriteLine("Here"); 
    } 
} 

vous serez alors bien sans avoir besoin d'appeler Cast. Je soupçonne que l'implémentation du code source de Cast est assez simple, même si je crois qu'elle a changé entre 3.5 et 3.5SP1. Cependant, il doit probablement mettre en place une nouvelle machine d'état, etc., à la manière d'un bloc d'itération normal. Mieux vaut l'éviter si possible.

Même si la nouvelle méthode est générique, l'inférence de type doit généralement en prendre soin pour vous, donc vous n'avez pas besoin de spécifier explicitement T.

+0

Cela pourrait changer complètement la question, mais que se passerait-il si A avait besoin d'une liste interne d'IB qui reflétait exactement la liste principale de A? – DevinB

+0

@devinb: Je ne suis pas vraiment sûr de ce que vous voulez dire. Voulez-vous dire en tant que variable membre? Vous auriez à faire un générique; alors vous pourriez utiliser le même tour. Si ce n'est pas assez d'information, je suggère que vous posiez une nouvelle question pour ce bit en donnant plus de détails. –

5

Pourquoi ne pas déclarer que la liste comme:

List<IB> aList = new List<IB>(); 

Y at-il quelque chose en particulier qui vous oblige à avoir une liste des classes concrètes?


Alors dans ce cas, je ferais de la liste une partie du domaine. Avoir une interface comme IIBCollection (par exemple), exposer les méthodes sur lesquelles vous voulez que le lecteur puisse accéder. Par exemple:

interface IIBCollection{ 
    IEnumerable<IB> IBs { get; } 
} 

// and in your implementation you can do 

IEnumerable<IB> IBs { 
    get { 
     foreach(IB ib in innerList) yield return ib; 
}} 
+0

Oui, car la classe principale doit gérer une liste des objets réels, mais la classe de lecture est uniquement autorisée à accéder à l'interface. – DevinB

+0

Désolé si je suis un peu lent. Mais vous dites que la classe principale (EnvironmentClass dans mon cas) devrait implémenter IIBCollection Je ne suis pas sûr de ce à quoi l'interface IIBCollection devrait s'appliquer. – DevinB

+0

Vous auriez quelque chose comme Environment, EnvironmentCollection, IEnvironment et IEnvironmentCollection. La méthode Go() vivrait sur la collection. – jonnii

1

Il est mis en œuvre en interne comme un CastIterator qui est légèrement plus lent qu'un foreach qui jette chaque élément.

0

La méthode Cast parcourra simplement la liste et lancera chaque élément.

Si vous comptez utiliser la liste des milliers de fois, il vous suffit de stocker le résultat du casting sous forme de liste.

Si cela n'est pas possible (c'est-à-dire que vous modifiez la liste à chaque fois), envisagez de travailler avec un List<IB> au lieu d'un List<A>.

0

N'est-ce pas ce à quoi sert la covariance en C#?Je ne vois pas ce que vous essayez de faire, donc je ne peux pas vous dire pourquoi cela a été exité des milliers et des milliers de fois.

0

Il serait assez simple de comparer les deux méthodes (méthode d'extension Cast et une boucle for avec un cast). Mais étant donné que Cast est une méthode d'extension de la classe Enumerable et traite génériquement avec IEnumerables, j'imagine que c'est précisément son implémentation. Si vous voulez la plus grande vitesse, il est préférable d'implémenter votre propre méthode d'extension qui fonctionne spécifiquement sur List (obtient chaque élément par son index), ce qui devrait être légèrement plus rapide compte tenu de la surcharge des itérateurs. Pourtant, les deux méthodes devraient prendre le temps O (n), donc la différence ne devrait pas être énorme. Cela peut néanmoins être utile ...