returns name documentacion c# .net linq internals

c# - name - ¿Por qué no devuelve Single() directamente cuando se encuentra más de un elemento?



param name c# (2)

Esta pregunta ya tiene una respuesta aquí:

Encontré (aproximadamente) este código en el método Enumerable.Single mientras lo inspeccionaba con un descompilador:

foreach (TSource current in source) { if (predicate(current)) { result = current; num += 1L; } } if (num > 1L) { throw Error.MoreThanOneMatch(); }

Como puede ver, recorre todos los elementos antes de lanzarlos. ¿Por qué no se rompe cuando num > 1 ?


De acuerdo, que será mejor en términos de rendimiento (EDITAR: si esperamos más de un elemento que coincida con nuestro predicado, lo que no deberíamos hacer):

foreach (TSource current in source) { if (predicate(current)) { result = current; num += 1L; if (num > 1L) throw Error.MoreThanOneMatch(); } } if (num == 0L) throw Error.NoMatch(); return local;

Parece que decidieron hacer que los resultados se analizaran más claramente y se separaron de la fuente de enumeración. Pero luego me pregunto por qué no se usó el simple interruptor:

switch((int)num) { case 0: throw Error.NoMatch(); case 1: return local; default: throw Error.MoreThanOneMatch(); }

Con respecto a los problemas de rendimiento, creo que se supone que se debe llamar a Single cuando realmente se espera un resultado único . Cero o más resultados es una ruta excepcional , que no debería ocurrir a menudo (como cualquier excepción). Por lo tanto, es más un error lógico de su programa si la fuente contiene muchos elementos que coinciden con el predicado.


Por Single se entiende exactamente uno, no ninguno y tampoco más de uno .
Enumera todos los elementos, para garantizar que sea uno solo.
Lanza una excepción, si no hay ninguna o más de una.
SingleOrDefault cambio, lanza si hay más, pero devuelve el default(T) / null si no hay ninguno.

Lo que está buscando es FirstOrDefault que rompe la enumeración, si encuentra que el primero coincide con el predicado. First lugar de lanzar, si no hay ninguno, y también se rompe (directamente regresa de) es foreach, si se encuentra el primero.

Fuente de FirstOrDefault

foreach (TSource current in source) { if (predicate(current)) { return current; } } return default(TSource);

Considerando que la fuente de First es en lugar de devolución por defecto

throw Error.NoMatch();