2009-01-31 12 views
28

Duplicar posible:
What does “yield break;” do in C#?¿De qué sirve el límite de rendimiento?

Puede alguien ver un uso para la declaración "yield break" que no se podría haber logrado de otra manera por el uso de "break" o "retorno".

Esta afirmación parece ser completamente inútil. Además, sin esta afirmación, la declaración de "retorno de rendimiento X" podría haberse simplificado a "rendimiento X", que es mucho más legible.

¿Qué me estoy perdiendo?

Respuesta

7

ruptura de rendimiento especifica que el método debe dejar de devolver los resultados. "return" por sí solo no sería lo suficientemente bueno, o podría incluso llevar a un error, porque el tipo de devolución del método debe ser IEnumerable.

No estoy seguro de por qué la palabra clave return también es necesaria. Mi mejor opción sería que ayuda a aclarar un poco la intención de la declaración.

Si usted está interesado, este artículo explica lo que el rendimiento está haciendo detrás de las escenas

Behind the scenes of the C# yield keyword

+0

Esa no es la forma en que leo el comportamiento: 'romper rendimientos' cancela todo el método y no devuelve nada. Podría tener elementos '10 return yield (ed)', pero si un 'yield break' es golpeado dentro del mismo método, obtiene 0 ítems en total. –

+1

@Dave: No lo creo ... ¿cómo va a funcionar la evaluación diferida en un bloque de iteradores? – chakrit

+4

@Dave, nope, yield break detiene la devolución de más elementos, pero no cancela (y no puede) lo que ya se ha devuelto. – configurator

0

Usted necesita tener una distinción entre volver una implementación IEnumerable que ya existe (tal vez usted va a devolver una List) y un iterador anónimo.

No se puede usar el retorno o el corte porque son palabras clave válidas que se pueden utilizar para otros fines. Tampoco puede usar el rendimiento por su cuenta porque necesita tener una forma de especificar si está devolviendo un artículo en la enumeración o terminando la enumeración, por lo tanto, la necesidad de rendimiento de retorno y rotura de rendimiento.

4

Es ilegal usar una instrucción return en un bloque iterador. Además, la declaración break podría tener un doble propósito dentro de un bloque iterador si se le permitiera afectar la iteración: podría usarse para salir de un bucle o fuera de un interruptor, y podría usarse para salir de un iterador. toda la iteración.

y yield break y son dos palabras clave en sí mismas, y ambas parecen ser necesarias.

1

return instrucción se utiliza para devolver un valor de una función.

Si usted tiene una función de iterador de esta manera:

public IEnumerable<int> IteratorOverInt() { } 

una sentencia return en la función anterior tendría que devolver un llenaron IEnumerable<int>.

public IEnumerable<int> IteratorOverInt() { 
    return new List<int> { 1, 2, 3, 4 }; 
} 

pero si usted está trabajando en una función de repetidor, que va a utilizar yield return, por lo que el código podría tener este aspecto:

public IEnumerable<int> IteratorOverInt() { 
    for (int i = 0; i < 4; i++) { 
     yield return i; 
    } 
} 

Así yield return devuelve un int mientras que la firma del método exige IEnumerable<int>

¿Qué haría una declaración return en el caso anterior? ¿Los resultados de devolución anulan los rendimientos? Concatenando lo que sea con los rendimientos? return no tiene mucho sentido en el caso anterior.

Por lo tanto, necesitamos una forma de return que tenga sentido en un bloque iterador, por lo que hay yield break.

Por supuesto que puedes hacerlo con un break, pero ¿cómo salir del cuerpo de la función si tienes más código que ejecutar? ¿Envolver todo en un complicado bloque if-else? Yo diría que solo tener yield break sería mejor.

51

Para dar un ejemplo de código, digamos que desea escribir un iterador que no devuelve nada si la fuente es nula o está vacía.

public IEnumerable<T> EnumerateThroughNull<T>(IEnumerable<T> source) 
{ 
    if (source == null) 
     yield break; 

    foreach (T item in source) 
     yield return item; 
} 

Sin el límite de rendimiento, resulta imposible devolver un conjunto vacío dentro de un iterador.

+0

@Cameron: gracias por esta muestra de código, ¡me ayudó con un problema que estaba teniendo! ¡Prestigio! –

+1

salto de rendimiento devuelve un enumerable vacío ... esencialmente (en su caso) lo mismo que 'devolver nuevo T [0]' pero sin crear un conjunto vacío. – Will

+2

Bueno, podríamos simplemente hacer que la sentencia if solo se ejecute si source! = Null, pero punto tomado – Casebash

4

ceder y romper hacer cosas completamente diferentes! Mira

for(int i = 0; i < 10; ++i) { 
    if(i > 5) { break; } 
    yield return i; 
} 

for(int v = 2710; v < 2714; v+=2) { 
    yield return v; 
} 

for(int s = 16; s < 147; ++s) { 
    if(s == 27) { yield break; } 
    else if(s > 17) { yield return s; } 
} 

salida sería un IEnumerable de estos valores: 0, 1, 2, 3, 4, 5, 2710, 2712, 18, 19, 20, 21, 22, 23, 24, 25, 26

Este es un método que no hace nada útil, pero ilustra que puede combinar el salto de rendimiento y el rompimiento en el mismo método, ¡y hacen dos cosas diferentes! La ruptura simplemente se rompe, el salto de rendimiento termina el método por completo.

Creo que el motivo por el que no se utiliza es porque no está devolviendo un IEnumerable en el método. Además, ¿no crees que la ruptura de rendimiento es más clara que el rendimiento, para este tipo de situación iterativa? Yo personalmente.

+0

lol oh whoops No quise que hiciera eso, lo arreglaré. –