Sin embargo, la documentación de MSDN lo menciona pero no lo explica. Esa es una mala manera de provocar a un desarrollador hambriento de conocimiento.
Phil
3
El rendimiento de rendimiento elimina la necesidad de una lista de respaldo, es decir, no necesita codificar algo como MyList.Add(...)simplemente hacer yield return .... Si necesita salir del bucle prematuramente y devolver la lista de respaldo virtual que usayield break;
The Muffin Man el
Respuestas:
529
Especifica que un iterador ha llegado a su fin. Puede pensar yield breakcomo una returndeclaración que no devuelve un valor.
Por ejemplo, si define una función como un iterador, el cuerpo de la función puede verse así:
for(int i =0; i <5; i++){yieldreturn i;}Console.Out.WriteLine("You will see me");
Tenga en cuenta que después de que el ciclo haya completado todos sus ciclos, se ejecuta la última línea y verá el mensaje en la aplicación de la consola.
O así con yield break:
int i =0;while(true){if(i <5){yieldreturn i;}else{// note that i++ will not be executed after thisyieldbreak;}
i++;}Console.Out.WriteLine("Won't see me");
En este caso, la última declaración nunca se ejecuta porque dejamos la función antes.
¿Podría ser simplemente en breaklugar de yield breaken su ejemplo anterior? El compilador no se queja de eso.
orad
85
@orad un simple breaken este caso detendría el ciclo, pero no abortaría la ejecución del método, por lo tanto, la última línea se ejecutaría y el "No me verá el texto" se vería realmente.
Damir Zekić
55
@Damir Zekić ¿Podría agregar también a su respuesta por qué preferiría el límite de rendimiento sobre el rendimiento y cuáles son las diferencias entre ambos?
Bruno Costa
11
@ DamirZekić regresando nulo y el límite de rendimiento no es lo mismo. Si devuelve nulo, puede NullReferenceExceptionobtener el enumerador de IEnumerable, mientras que con el límite de rendimiento no lo hace (hay una instancia sin elementos).
Bruno Costa
66
@BrunoCosta Intentar obtener retornos regulares en el mismo método da un error de compilación. Usando yield return xalertas el compilador quiere que este método sea azúcar sintáctico para crear un Enumeratorobjeto. Este enumerador tiene método MoveNext()y propiedad Current. MoveNext () ejecuta el método hasta una yield returndeclaración y convierte ese valor en Current. La próxima vez que se llama a MoveNext, la ejecución continúa desde allí. yield breakestablece Current en nulo, señalando el final de este enumerador, para que foreach (var x in myEnum())finalice a.
Wolfzoon
57
Finaliza un bloque iterador (por ejemplo, dice que no hay más elementos en IEnumerable).
con [+1], aunque académicamente no hay iteradores en .NET. solo enumeradores (una dirección, hacia adelante)
Shaun Wilson
@Shaun Wilson, pero con la yieldpalabra clave puede iterar la colección en ambas direcciones, además, puede tomar todos los elementos siguientes de la colección que no
estén
@monstr puede iterar la colección de cualquier manera y no necesita yieldhacerlo. No digo que te equivoques, veo lo que estás sugiriendo; pero, académicamente, no hay iteradores en .NET, solo enumeradores (una dirección, hacia adelante): a diferencia de stdc ++, no hay un "marco de iterador genérico" definido en el CTS / CLR. LINQ ayuda a cerrar la brecha con métodos de extensión que utilizan yield returny también métodos de devolución de llamada , pero son métodos de extensión de primera clase, no iteradores de primera clase. lo resultante IEnumerableno puede iterar en ninguna otra dirección que no sea hacia adelante con la persona que llama.
Shaun Wilson
29
Le dice al iterador que ha llegado al final.
Como ejemplo:
publicinterfaceINode{IEnumerable<Node>GetChildren();}publicclassNodeWithTenChildren:INode{privateNode[] m_children =newNode[10];publicIEnumerable<Node>GetChildren(){for(int n =0; n <10;++n ){yieldreturn m_children[ n ];}}}publicclassNodeWithNoChildren:INode{publicIEnumerable<Node>GetChildren(){yieldbreak;}}
yieldbásicamente hace que un IEnumerable<T>método se comporte de manera similar a un hilo programado de forma cooperativa (en lugar de preventivamente).
yield returnes como un hilo que llama a una función de "programación" o "suspensión" para ceder el control de la CPU. Al igual que un subproceso, el IEnumerable<T>método recupera los controles en el punto inmediatamente posterior, con todas las variables locales que tienen los mismos valores que tenían antes de ceder el control.
yield break es como un hilo que llega al final de su función y termina.
La gente habla de una "máquina de estado", pero una máquina de estado es todo un "hilo". Un subproceso tiene algún estado (es decir, valores de variables locales), y cada vez que se programa toma algunas acciones para alcanzar un nuevo estado. El punto clave yieldes que, a diferencia de los subprocesos del sistema operativo a los que estamos acostumbrados, el código que lo usa se congela en el tiempo hasta que la iteración se avanza o finaliza manualmente.
La yield breakdeclaración hace que la enumeración se detenga. En efecto, yield breakcompleta la enumeración sin devolver ningún elemento adicional.
Considere que en realidad hay dos formas en que un método iterador podría dejar de iterar. En un caso, la lógica del método podría salir naturalmente del método después de devolver todos los elementos. Aquí hay un ejemplo:
IEnumerable<uint>FindPrimes(uint startAt,uint maxCount){for(var i =0UL; i < maxCount; i++){
startAt =NextPrime(startAt);yieldreturn startAt;}Debug.WriteLine("All the primes were found.");}
En el ejemplo anterior, el método iterador naturalmente dejará de ejecutarse una vez que maxCountse hayan encontrado los números primos.
La yield breakdeclaración es otra forma para que el iterador deje de enumerar. Es una forma de salir temprano de la enumeración. Aquí está el mismo método que el anterior. Esta vez, el método tiene un límite en la cantidad de tiempo que puede ejecutar el método.
IEnumerable<uint>FindPrimes(uint startAt,uint maxCount,int maxMinutes){var sw =System.Diagnostics.Stopwatch.StartNew();for(var i =0UL; i < maxCount; i++){
startAt =NextPrime(startAt);yieldreturn startAt;if(sw.Elapsed.TotalMinutes> maxMinutes)yieldbreak;}Debug.WriteLine("All the primes were found.");}
Observe la llamada a yield break. En efecto, está saliendo de la enumeración temprano.
Tenga en cuenta también que yield breakfunciona de manera diferente a un simple break. En el ejemplo anterior, yield breaksale del método sin realizar la llamada a Debug.WriteLine(..).
Public static IEnumerable <int> Range (int min, int max)
{
mientras (cierto)
{
si (min> = max)
{
ruptura de rendimiento;
}
rendimiento de rendimiento min ++;
}
}
y explicación, que si yield breakse golpea una declaración dentro de un método, la ejecución de ese método se detiene sin retorno. Hay algunas situaciones de tiempo, cuando no quieres dar ningún resultado, entonces puedes usar el límite de rendimiento.
Bueno, solo son complicados si te importa el código en el que están compilados. El código que los usa es bastante simple.
Robert Rossney
@Robert, a eso me refería, así que actualicé la respuesta para incluir tu comentario
Tony Lee
-2
La palabra clave de rendimiento se usa junto con la palabra clave de retorno para proporcionar un valor al objeto enumerador. return return especifica el valor o valores devueltos. Cuando se alcanza la declaración de rendimiento, se almacena la ubicación actual. La ejecución se reinicia desde esta ubicación la próxima vez que se llama al iterador.
Los valores devueltos cuando esto se repite son: 0, 2, 5.
Es importante tener en cuenta que la variable de contador en este ejemplo es una variable local. Después de la segunda iteración que devuelve el valor de 2, la tercera iteración comienza desde donde dejó antes, mientras se conserva el valor anterior de la variable local denominada contador que era 2.
No creo que yield returnrealmente sea compatible con la devolución de múltiples valores. Tal vez eso no es lo que realmente quisiste decir, pero así es como lo leí.
Sam
Sam: el método SampleNumbers con múltiples declaraciones de rendimiento de rendimiento funciona, el valor del iterador se devuelve inmediatamente y la ejecución se reanuda cuando se solicita el siguiente valor. He visto a personas terminar un método como este con un "límite de rendimiento", pero es innecesario. Llegar al final del método también finaliza el iterador
Loren Paulsen
la razón por la que este es un mal ejemplo yield breakes que no contiene un enumerador de nivel de lenguaje como un foreach- cuando se usa un enumerador, yield breakproporciona un valor real. Este ejemplo parece un bucle desenrollado. casi nunca verá este código en el mundo real (todos podemos pensar en algunos casos extremos, claro) también, no hay un "iterador" aquí. el "bloque iterador" no puede extenderse más allá del método como una cuestión de especificación de lenguaje. lo que realmente se devuelve es un "enumerable", vea también: stackoverflow.com/questions/742497/…
MyList.Add(...)
simplemente haceryield return ...
. Si necesita salir del bucle prematuramente y devolver la lista de respaldo virtual que usayield break;
Respuestas:
Especifica que un iterador ha llegado a su fin. Puede pensar
yield break
como unareturn
declaración que no devuelve un valor.Por ejemplo, si define una función como un iterador, el cuerpo de la función puede verse así:
Tenga en cuenta que después de que el ciclo haya completado todos sus ciclos, se ejecuta la última línea y verá el mensaje en la aplicación de la consola.
O así con
yield break
:En este caso, la última declaración nunca se ejecuta porque dejamos la función antes.
fuente
break
lugar deyield break
en su ejemplo anterior? El compilador no se queja de eso.break
en este caso detendría el ciclo, pero no abortaría la ejecución del método, por lo tanto, la última línea se ejecutaría y el "No me verá el texto" se vería realmente.NullReferenceException
obtener el enumerador de IEnumerable, mientras que con el límite de rendimiento no lo hace (hay una instancia sin elementos).yield return x
alertas el compilador quiere que este método sea azúcar sintáctico para crear unEnumerator
objeto. Este enumerador tiene métodoMoveNext()
y propiedadCurrent
. MoveNext () ejecuta el método hasta unayield return
declaración y convierte ese valor enCurrent
. La próxima vez que se llama a MoveNext, la ejecución continúa desde allí.yield break
establece Current en nulo, señalando el final de este enumerador, para queforeach (var x in myEnum())
finalice a.Finaliza un bloque iterador (por ejemplo, dice que no hay más elementos en IEnumerable).
fuente
yield
palabra clave puede iterar la colección en ambas direcciones, además, puede tomar todos los elementos siguientes de la colección que noyield
hacerlo. No digo que te equivoques, veo lo que estás sugiriendo; pero, académicamente, no hay iteradores en .NET, solo enumeradores (una dirección, hacia adelante): a diferencia de stdc ++, no hay un "marco de iterador genérico" definido en el CTS / CLR. LINQ ayuda a cerrar la brecha con métodos de extensión que utilizanyield return
y también métodos de devolución de llamada , pero son métodos de extensión de primera clase, no iteradores de primera clase. lo resultanteIEnumerable
no puede iterar en ninguna otra dirección que no sea hacia adelante con la persona que llama.Le dice al iterador que ha llegado al final.
Como ejemplo:
fuente
yield
básicamente hace que unIEnumerable<T>
método se comporte de manera similar a un hilo programado de forma cooperativa (en lugar de preventivamente).yield return
es como un hilo que llama a una función de "programación" o "suspensión" para ceder el control de la CPU. Al igual que un subproceso, elIEnumerable<T>
método recupera los controles en el punto inmediatamente posterior, con todas las variables locales que tienen los mismos valores que tenían antes de ceder el control.yield break
es como un hilo que llega al final de su función y termina.La gente habla de una "máquina de estado", pero una máquina de estado es todo un "hilo". Un subproceso tiene algún estado (es decir, valores de variables locales), y cada vez que se programa toma algunas acciones para alcanzar un nuevo estado. El punto clave
yield
es que, a diferencia de los subprocesos del sistema operativo a los que estamos acostumbrados, el código que lo usa se congela en el tiempo hasta que la iteración se avanza o finaliza manualmente.fuente
Todo el tema de los bloques iteradores se trata bien en este capítulo de muestra gratuito del libro C # en profundidad de Jon Skeet .
fuente
La
yield break
declaración hace que la enumeración se detenga. En efecto,yield break
completa la enumeración sin devolver ningún elemento adicional.Considere que en realidad hay dos formas en que un método iterador podría dejar de iterar. En un caso, la lógica del método podría salir naturalmente del método después de devolver todos los elementos. Aquí hay un ejemplo:
En el ejemplo anterior, el método iterador naturalmente dejará de ejecutarse una vez que
maxCount
se hayan encontrado los números primos.La
yield break
declaración es otra forma para que el iterador deje de enumerar. Es una forma de salir temprano de la enumeración. Aquí está el mismo método que el anterior. Esta vez, el método tiene un límite en la cantidad de tiempo que puede ejecutar el método.Observe la llamada a
yield break
. En efecto, está saliendo de la enumeración temprano.Tenga en cuenta también que
yield break
funciona de manera diferente a un simplebreak
. En el ejemplo anterior,yield break
sale del método sin realizar la llamada aDebug.WriteLine(..)
.fuente
Aquí http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ es un muy buen ejemplo:
y explicación, que si
yield break
se golpea una declaración dentro de un método, la ejecución de ese método se detiene sin retorno. Hay algunas situaciones de tiempo, cuando no quieres dar ningún resultado, entonces puedes usar el límite de rendimiento.fuente
el límite de rendimiento es solo una forma de decir retorno por última vez y no devolver ningún valor
p.ej
fuente
Si lo que quiere decir con "lo que realmente hace la ruptura del rendimiento" es "cómo funciona", consulte el blog de Raymond Chen para obtener más información. https://devblogs.microsoft.com/oldnewthing/20080812-00/?p=21273
Los iteradores de C # generan un código muy complicado.
fuente
La palabra clave de rendimiento se usa junto con la palabra clave de retorno para proporcionar un valor al objeto enumerador. return return especifica el valor o valores devueltos. Cuando se alcanza la declaración de rendimiento, se almacena la ubicación actual. La ejecución se reinicia desde esta ubicación la próxima vez que se llama al iterador.
Para explicar el significado usando un ejemplo:
Los valores devueltos cuando esto se repite son: 0, 2, 5.
Es importante tener en cuenta que la variable de contador en este ejemplo es una variable local. Después de la segunda iteración que devuelve el valor de 2, la tercera iteración comienza desde donde dejó antes, mientras se conserva el valor anterior de la variable local denominada contador que era 2.
fuente
yield break
haceyield return
realmente sea compatible con la devolución de múltiples valores. Tal vez eso no es lo que realmente quisiste decir, pero así es como lo leí.yield break
es que no contiene un enumerador de nivel de lenguaje como unforeach
- cuando se usa un enumerador,yield break
proporciona un valor real. Este ejemplo parece un bucle desenrollado. casi nunca verá este código en el mundo real (todos podemos pensar en algunos casos extremos, claro) también, no hay un "iterador" aquí. el "bloque iterador" no puede extenderse más allá del método como una cuestión de especificación de lenguaje. lo que realmente se devuelve es un "enumerable", vea también: stackoverflow.com/questions/742497/…