c# - que - ¿Cuáles son las aplicaciones del rendimiento en la vida real?
yield return c# stack overflow (7)
Sé lo que hace el yield
, 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 se puede resolver de otra manera)
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, generalmente utilizando 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 usar para implementar otros tipos de evaluación diferida donde las expresiones se evalúan solo cuando lo necesita. También puedes usar yield para cosas más sofisticadas como corutinas.
Otro buen uso del rendimiento es realizar una función en los elementos de un IEnumerable y 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);
}
Un uso interesante es como un mecanismo para la programación asincrónica esp 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 Parte 1 y Parte 2 . El tiempo de concurrencia y coordinación (CCR) también hace uso de esta técnica de Iteradores CCR .
Usar el rendimiento puede evitar la bajada a un tipo concreto. Esto es útil para garantizar que el consumidor de la colección no lo manipule.
en realidad lo uso de forma 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, comprueba si la visualización de la idea está actualmente autorizada 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.
También puede 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. Uno 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);
}
}
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 la 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 usar 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).
Respecto a:
Ideally some problem that cannot be solved some other way
La declaración de rendimiento no le proporciona nada que no pueda hacer utilizando su propia implementación personalizada de iterador, pero le ahorra la necesidad de escribir el código, a menudo complejo, que se necesita. 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: