2008-08-19 15 views

Respuesta

8

Me doy cuenta de que esta es una pregunta antigua (¿antes de Jon Skeet?) Pero últimamente he estado considerando esta pregunta. Desafortunadamente, las respuestas actuales aquí (en mi opinión) no mencionan la ventaja más obvia de la declaración de rendimiento.

El mayor beneficio de la declaración de rendimiento es que le permite iterar en listas muy grandes con un uso de memoria mucho más eficiente que utilizando, por ejemplo, una lista estándar.

Por ejemplo, supongamos que tiene una consulta de base de datos que devuelve 1 millón de filas. Puede recuperar todas las filas utilizando un DataReader y almacenarlas en una lista, por lo que requiere list_size * row_size bytes de memoria.

O puede utilizar la declaración de rendimiento para crear un iterador y solo almacenar una fila en la memoria a la vez. En efecto, esto le da la capacidad de proporcionar una capacidad de "transmisión" sobre grandes conjuntos de datos.

Además, en el código que usa el iterador, utiliza un bucle foreach simple y puede decidir salir del bucle según sea necesario.Si se rompe temprano, no ha forzado la recuperación de todo el conjunto de datos cuando solo necesitaba las primeras 5 filas (por ejemplo).

Con respecto a:

Ideally some problem that cannot be solved some other way 

comunicado El rendimiento no le da nada que no podía hacer uso de su propia implementación personalizada iterador, pero le ahorra necesidad de escribir el código a menudo compleja sea necesario. Hay muy pocos problemas (si los hay) que no se pueden resolver de más de una manera.

Aquí hay un par de preguntas y respuestas más recientes que proporcionan más detalles:

Yield keyword value added?

Is yield useful outside of LINQ?

5

realidad lo uso de manera no tradicional en mi sitio IdeaPipe

public override IEnumerator<T> GetEnumerator() 
{ 
    // goes through the collection and only returns the ones that are visible for the current user 
    // this is done at this level instead of the display level so that ideas do not bleed through 
    // on services 
    foreach (T idea in InternalCollection) 
     if (idea.IsViewingAuthorized) 
      yield return idea; 
} 

así que básicamente se comprueba si está viendo la idea es actualmente autorizado y si lo es devuelve la idea. Si no es así, solo se salta. Esto me permite almacenar en caché las ideas pero aún mostrar las ideas a los usuarios que están autorizados. De lo contrario, tendría que volver a extraerlos cada vez según los permisos, cuando solo se vuelven a clasificar cada 1 hora.

1

Los operadores de LINQ en la clase Enumerable se implementan como iteradores que se crean con la declaración de rendimiento. Le permite encadenar operaciones como Select() y Where() sin enumerar nada hasta que realmente usa el enumerador en un bucle, normalmente usando la instrucción foreach. Además, dado que solo se calcula un valor cuando se llama a IEnumerator.MoveNext() si decide detener la recopilación media, se guardará el resultado de rendimiento al calcular todos los resultados.

Los iteradores también se pueden utilizar para implementar otros tipos de evaluación perezosa donde las expresiones se evalúan solo cuando lo necesita. También puede usar para obtener y obtener más detalles como corutinas.

1

Otro buen uso para el rendimiento es para realizar una función en los elementos de IEnumerable y para devolver un resultado de un tipo diferente, por ejemplo:

public delegate T SomeDelegate(K obj); 

public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action) 
{ 
    foreach (var i in list) 
     yield return action(i); 
} 
2

Un uso interesante es como un mecanismo de programación asincrónica especialmente para tareas que toman varios pasos y requieren el mismo conjunto de datos en cada paso. Dos ejemplos de esto serían Jeffery Richters AysncEnumerator Part 1 y Part 2. El tiempo de concurrencia y coordinación (CCR) también hace uso de esta técnica CCR Iterators.

1

El uso del rendimiento puede evitar la bajada a un tipo concreto. Esto es útil para garantizar que el consumidor de la colección no lo manipule.

0

También puede utilizar yield return para tratar una serie de resultados de la función como una lista. Por ejemplo, considere una empresa que paga a sus empleados cada dos semanas. Uno podría recuperar un subconjunto de fechas de nómina como una lista con este código:

void Main() 
{ 
    var StartDate = DateTime.Parse("01/01/2013"); 
    var EndDate = DateTime.Parse("06/30/2013"); 
    foreach (var d in GetPayrollDates(StartDate, EndDate)) { 
     Console.WriteLine(d); 
    } 
} 

// Calculate payroll dates in the given range. 
// Assumes the first date given is a payroll date. 
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int  daysInPeriod = 14) { 
    var thisDate = startDate; 
    while (thisDate < endDate) { 
     yield return thisDate; 
     thisDate = thisDate.AddDays(daysInPeriod); 
    } 
} 
Cuestiones relacionadas