Pregunta

yo se que yield lo hace, y he visto algunos ejemplos, pero no puedo pensar en aplicaciones de la vida real, ¿lo has usado para resolver algún problema específico?

(Idealmente algún problema que no pueda resolverse de otra manera)

¿Fue útil?

Solución

Me doy cuenta de que esta es una vieja pregunta (¿anterior a Jon Skeet?), Pero yo también he estado considerando esta pregunta últimamente.Lamentablemente, 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 sobre listas muy grandes con un uso de memoria mucho más eficiente que usar, por ejemplo, una lista estándar.

Por ejemplo, digamos 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 podría usar la declaración de rendimiento para crear un iterador y almacenar solo una fila en la memoria a la vez.De hecho, esto le brinda la capacidad de proporcionar una capacidad de "transmisión" sobre grandes conjuntos de datos.

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

Acerca de:

Ideally some problem that cannot be solved some other way

La declaración de rendimiento no le brinda nada que no pueda hacer usando su propia implementación de iterador personalizado, pero le ahorra la necesidad de escribir el código, a menudo complejo, necesario.Hay muy pocos problemas (si es que hay alguno) que no se puedan resolver de más de una manera.

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

¿Valor agregado de palabras clave de rendimiento?

¿Es útil el rendimiento fuera de LINQ?

Otros consejos

De hecho, lo uso de forma no tradicional en mi sitio. Tubo de ideas

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

Básicamente, comprueba si ver la idea está actualmente autorizado y, si lo está, devuelve la idea.Si no es así, simplemente se omite.Esto me permite almacenar en caché las ideas pero aún mostrarlas a los usuarios autorizados.De lo contrario, tendría que volver a extraerlos cada vez según los permisos, cuando solo se reclasifican cada hora.

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

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 use el enumerador en un bucle, generalmente usando el para cada declaración.Además, dado que solo se calcula un valor cuando llama a IEnumerator.MoveNext() si decide detener la recopilación a mitad de camino, se ahorrará el impacto en el rendimiento al calcular todos los resultados.

Los iteradores también se pueden usar para implementar otros tipos de evaluación diferida donde las expresiones se evalúan solo cuando lo necesita.También puedes usar producir para cosas más sofisticadas como corrutinas.

Otro buen uso de rendimiento es realizar una función sobre los elementos de un IEnumerable y devolver un resultado de diferente tipo, 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);
}

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

También puedes usar yield return para tratar una serie de resultados de funciones como una lista.Por ejemplo, considere una empresa que paga a sus empleados cada dos semanas.Se podría recuperar un subconjunto de fechas de nómina como una lista usando 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);
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top