He visto esta sintaxis en MSDN: yield break
pero no sé qué hace. ¿Alguien sabe?
MyList.Add(...)
simplemente hacer yield return ...
. Si necesita salir del bucle prematuramente y devolver la lista de respaldo virtual que usayield break;
He visto esta sintaxis en MSDN: yield break
pero no sé qué hace. ¿Alguien sabe?
MyList.Add(...)
simplemente hacer yield 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 una return
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í:
for (int i = 0; i < 5; i++)
{
yield return 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)
{
yield return i;
}
else
{
// note that i++ will not be executed after this
yield break;
}
i++;
}
Console.Out.WriteLine("Won't see me");
En este caso, la última declaración nunca se ejecuta porque dejamos la función antes.
break
lugar de yield 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 un Enumerator
objeto. Este enumerador tiene método MoveNext()
y propiedad Current
. MoveNext () ejecuta el método hasta una yield return
declaración y convierte ese valor en Current
. 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 que foreach (var x in myEnum())
finalice a.
Finaliza un bloque iterador (por ejemplo, dice que no hay más elementos en IEnumerable).
yield
palabra clave puede iterar la colección en ambas direcciones, además, puede tomar todos los elementos siguientes de la colección que no
yield
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 utilizan yield 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 resultante IEnumerable
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:
public interface INode
{
IEnumerable<Node> GetChildren();
}
public class NodeWithTenChildren : INode
{
private Node[] m_children = new Node[10];
public IEnumerable<Node> GetChildren()
{
for( int n = 0; n < 10; ++n )
{
yield return m_children[ n ];
}
}
}
public class NodeWithNoChildren : INode
{
public IEnumerable<Node> GetChildren()
{
yield break;
}
}
yield
bá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 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, 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 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.
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 .
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:
IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
for (var i = 0UL; i < maxCount; i++)
{
startAt = NextPrime(startAt);
yield return startAt;
}
Debug.WriteLine("All the primes were found.");
}
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.
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);
yield return startAt;
if (sw.Elapsed.TotalMinutes > maxMinutes)
yield break;
}
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 break
funciona de manera diferente a un simple break
. En el ejemplo anterior, yield break
sale del método sin realizar la llamada a Debug.WriteLine(..)
.
Aquí http://www.alteridem.net/2007/08/22/the-yield-statement-in-c/ es un muy buen ejemplo:
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 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.
el límite de rendimiento es solo una forma de decir retorno por última vez y no devolver ningún valor
p.ej
// returns 1,2,3,4,5
IEnumerable<int> CountToFive()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
yield break;
yield return 6;
yield return 7;
yield return 8;
yield return 9;
}
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.
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:
public IEnumerable<int> SampleNumbers() { int counter = 0; yield return counter; counter = counter + 2; yield return counter; counter = counter + 3; yield return counter ; }
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.
yield break
hace
yield 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 un foreach
- 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/…