Pregunta

Tengo el siguiente código

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

}

Originalmente intenté pasar una Lista pero eso no funciona . Después de mucha ayuda de SO descubrí que pasar IEnumerable es el única forma de obtener los objetos a través de .ofType (IB).

Desafortunadamente para mí, en mi código, la siguiente línea se ejecutará miles de veces:

aList.Cast<IB>();

Me preguntaba si alguien sabía cómo se implementó de forma algorítmica (en IL) y cuál es su orden temporal.

Es decir, ¿es más rápido que un bucle foreach que solo lanza cada elemento, o es exactamente lo que hace?

EDIT La clase principal necesita mantener una lista de los objetos reales. Pero al lector solo se le permite tocarlos a través de la interfaz.

¿Fue útil?

Solución

Debes cambiar Go a:

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

Entonces estarás bien sin necesidad de llamar a Cast . Sospecho que la implementación del código fuente de Cast es bastante simple, aunque creo que cambió entre 3.5 y 3.5SP1. Sin embargo, es probable que necesite configurar una nueva máquina de estados, etc. en la forma normal del bloque de iteradores. Mejor evitarlo si es posible.

A pesar de que el nuevo método es genérico, la inferencia de tipos por lo general debería encargarse de él, por lo que no es necesario que especifique T explícitamente.

Otros consejos

¿Por qué no simplemente declarar la lista como:

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

¿Hay algo en particular que requiera que tengas una lista de las clases concretas?


Entonces, en ese caso, haría que la lista fuera parte del dominio. Tenga una interfaz como IIBCollection (por ejemplo), exponga los métodos a los que desea que el lector pueda acceder. Por ejemplo:

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

Se implementa internamente como CastIterator, que es un poco más lento que un foreach que lanza cada elemento.

El método de Cast solo recorrerá la lista y emitirá cada elemento.

Si va a usar la lista miles de veces, simplemente almacene el resultado de la transmisión como una lista.

Si eso no es posible (es decir, cambia la lista cada vez), considere trabajar con una List < IB > en lugar de una List < A > .

¿No es esto para lo que es la covarianza en C #? No veo lo que estás tratando de hacer, así que no puedo comentar por qué se ha ejecutado miles y miles de veces.

Sería una cuestión bastante simple comparar los dos métodos (método de extensión Cast y un bucle for con un cast). Pero dado que Cast es un método de extensión de la clase Enumerable y trata genéricamente con IEnumerables, me imagino que esto es precisamente su implementación. Si desea la mayor velocidad, puede ser mejor implementar su propio método de extensión que funcione específicamente en Lista (obtiene cada elemento por su índice), que debería ser un poco más rápido dada la sobrecarga de iteradores. Aún así, ambos métodos deberían llevar tiempo O (n), por lo que la diferencia no debería ser enorme. Es algo que vale la pena comparar, sin embargo ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top