Question

J'ai le code suivant

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

}

Au départ, j'ai essayé de passer une liste, mais ne fonctionne pas . Après beaucoup d'aide de SO , j'ai constaté que le passage d'IEnumerable était la seul moyen de faire passer les objets en tant que .ofType (IB).

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

aList.Cast<IB>();

Je me demandais si quelqu'un savait comment cela était implémenté par algorithme (en IL) et quel était son ordre chronologique.

C'est-à-dire, est-ce plus rapide qu'une boucle foreach qui lance chaque élément ou est-ce exactement ce qu'elle fait?

MODIFIER la classe principale doit conserver une liste des objets réels. Mais le lecteur n'est autorisé à les toucher que via l'interface.

Était-ce utile?

La solution

Vous devriez changer Go en:

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

Alors tout ira bien sans avoir à appeler Diffuser . Je soupçonne que l’implémentation du code source de Cast est assez simple, bien que je pense qu’elle a changé entre 3.5 et 3.5SP1. Cependant, il doit probablement configurer une nouvelle machine à états, etc. de la manière habituelle par bloc d'itérateur. Mieux vaut l'éviter si possible.

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

Autres conseils

Pourquoi ne pas déclarer la liste comme suit:

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

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

Donc, dans ce cas, je ferais partie de la liste du domaine. Si vous avez une interface comme IIBCollection (par exemple), exposez les méthodes auxquelles vous souhaitez 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; 
}}

Il est implémenté de manière interne en tant que CastIterator, ce qui est légèrement plus lent que forfor qui lance chaque élément.

La méthode Cast se contentera de parcourir la liste en boucle et de convertir chaque élément.

Si vous comptez utiliser la liste des milliers de fois, stockez simplement le résultat de la diffusion sous forme de liste.

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

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

Il serait assez simple de comparer les deux méthodes (méthode d'extension Cast et une boucle for avec casting). Mais étant donné que Cast est une méthode d'extension de la classe Enumerable et traite de manière générique avec IEnumerables, j'imagine que c'est précisément son implémentation. Si vous voulez la plus grande vitesse, il peut être 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. Néanmoins, les deux méthodes devraient prendre O (n) temps, la différence ne devrait donc pas être énorme. C'est quelque chose qui mérite d'être comparé, néanmoins ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top