Pregunta

Hace un tiempo escribí un IList Método de extensión para enumerar en parte de una lista utilizando los índices. Mientras se refactoraba, me di cuenta de que se podía realizar una consulta similar llamando Skip(toSkip).Take(amount). Mientras comparaba esto, noté que Skip no está optimizado para IList. Con un poco de Google terminé en un Jon Skeet Post, Discutir por qué optimizar métodos como Skip es peligroso.

Hasta donde entiendo, el artículo, el problema no es una excepción en los métodos optimizados cuando la colección se modifica, pero como un comentario establece, la documentación de MSDN entra en conflicto.

En IEnumerator.movenext ():

Si se realizan cambios en la colección, como agregar, modificar o eliminar elementos, el enumerador se invalida irralidados y la próxima llamada a MoveNext o reiniciar Lanza una InvalioperationException.

En Ienumerator.getEnumerator ():

Si se realizan cambios en la colección, como agregar, modificar o eliminar elementos, el enumerador se invalida irralidados y su comportamiento es indefinido.

Veo mérito en ambas convenciones, y estoy un poco perdido si optimizar o no. ¿Qué es una solución adecuada? He estado considerando un IList.AssumeImmutable() acercarse en la línea de AsParallel() como lo mencionó Kris Vandermotten en los comentarios. ¿Ya existe alguna implementación o es una mala idea?

¿Fue útil?

Solución

Estoy de acuerdo con Rafe en que el comportamiento indefinido es más correcto. Solo las colecciones versionadas pueden lanzar excepciones y no todas las colecciones están versión (las matrices son el ejemplo más grande). Incluso las colecciones versionadas pueden comportarse mal si realiza exactamente 2^32 cambios entre llamadas a MoveNext.

Suponiendo que realmente te importa el comportamiento de versiones, la solución es obtener un Enumerator Para el IList y llama MoveNext en él para cada iteración:

    public static IEnumerable<T> Skip<T>(this IList<T> source, int count)
    {
        using (var e = source.GetEnumerator())
            while (count < source.Count && e.MoveNext())
                yield return source[count++];
    }

De esta manera obtienes el comportamiento de O (1) al indexar, pero aún obtienes todo el comportamiento de excepción de llamadas de llamadas MoveNext. Tenga en cuenta que solo llamamos MoveNext Para la excepción de efectos secundarios; Ignoramos los valores sobre los que está enumerando.

Otros consejos

los ReadonlyCollection La clase podría ayudar con su colección inmutable.

Mi consejo: personalmente no intentaría "engañar" al compilador a menos que tenga un problema de rendimiento. Nunca se sabe, la próxima versión podría hacer que su código optimizado se ejecute dos veces tan lento que el original. No optimice preventivamente. Los métodos proporcionados en el marco pueden producir un código realmente optimizado que sería difícil de volver a implementar.

aquí es un artículo de MSDN que proporciona información sobre qué colecciones usar para diferentes fines. Usaría una colección apropiada para la tarea en lugar de tratar de optimizar omitir y tomar.

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