2010-07-05 7 views
5

consideran este código:Entender la extensión ElementAt (índice)

int size = 100 * 1000 * 1000; 
var emu = Enumerable.Range(0, size); 
var arr = Enumerable.Range(0, size).ToArray(); 

cuando llamo emu.ElementAt (tamaño 10) y arr.ElementAt (tamaño 10) y medir el tiempo que el arr es mucho más rápido (el conjunto es 0.0002s en comparación con IEnumerable 0.59s).

Según tengo entendido, el método de extensión ElementAt() tiene la firma

public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int index) 

y desde la 'fuente' es un IEnumerable la lógica llevada a cabo sería similar - en contraposición a lo que veo en la matriz se accede directamente.

Podría alguien explicar esto :)

Respuesta

5

Esta es una optimización realizada en tiempo de ejecución. Aunque la llamada no está sobrecargada, puede verificar (utilizando is o as) si la fuente es realmente IList<T>. Si es así, puede ir directamente al elemento correcto.

Varias otras llamadas hacer esto - notable Count() que está optimizado para ICollection<T> y (como de .NET 4) la interfaz no genérico ICollection.

Una de las desventajas de los métodos de extensión es que todas estas optimizaciones deben ser realizadas por la propia implementación: los tipos no pueden anular nada para "habilitar" la optimización de los métodos de extensión. Eso significa que todas las optimizaciones deben ser conocidas por el implementador original :(

+0

Puede optar indirectamente por las optimizaciones haciendo que su tipo de colección personalizada implemente 'IList ', pero impleméntelo explícitamente y/o exponga públicamente su colección como 'IEnumerable '. No es ideal, pero básicamente estos son los 'ganchos' de optimización. Si lo desea, podría proporcionar una interfaz personalizada para cada método de extensión personalizado que permita a un escritor de clase anular el comportamiento del método de extensión, aunque esto podría ser un poco desordenado. Algo como 'WidgetExtensions.ToggleWidget (este widget Widget) 'y' WidgetExtensions.IToggleWidget '. –

12

Calling ElementAt en un bucle IEnumerable<T> voluntad a través de los artículos hasta que alcanza el índice deseado. (Una operación O (n))

Calling ElementAt en una IList<T> (tal como una matriz) utilizará indexador la IList<T> 's para obtener inmediatamente el índice deseado. (Una operación O (1))

+0

Arh, entonces usted me está diciendo que ElementAt está sobrecargado para Arrays, Lists, Whatnot ... ?? – Moberg

+1

No está sobrecargado. Utiliza un tipo de conversión – SLaks