¿Cuándo usar .First y cuándo usar .FirstOrDefault con LINQ?

824

He buscado y realmente no he encontrado una respuesta clara sobre cuándo querría usar .Firsty cuándo querría usar .FirstOrDefaultcon LINQ.

  • ¿Cuándo te gustaría usar .First? ¿Solo cuando desee capturar la excepción si no se devuelven resultados?

    var result = List.Where(x => x == "foo").First();
  • ¿Y cuándo te gustaría usar .FirstOrDefault? ¿Cuándo siempre quieres el tipo predeterminado si no hay resultado?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • Y para el caso, ¿qué pasa con Take?

    var result = List.Where(x => x == "foo").Take(1);
Metro Pitufo
fuente
86
.Firsty .FirstOrDefaultambos toman predicados como argumentos, por lo que var result = List.Where(x => x == "foo").First();podrían reescribirse comovar result = List.First(x => x == "foo");
Rian Schmits
59
No te olvides de considerar Singley SingleOrDefault. Odio cuando las personas usan Firstcuando realmente quieren decir Single; )
BartoszKP
19
¡Single o SingleOrDefault arrojaría una excepción si hay más de un elemento devuelto! ¡Creo que FirstOrDefault es mejor en la mayoría de los casos comunes!
Eric Draven
21
El punto es que cuando espera un resultado único, debe decirlo, y la excepción indica que su lógica falló.
NetMage
1
También considere que usar .FirstOrDefault()siempre le brinda la oportunidad de lanzar una excepción más significativa. Si se produce una excepción de secuencia y más de una .First()en un método, puede ser difícil discernir qué enunciado es el problema.
StingyJack

Respuestas:

807

yo usaría First() cuando conozco o espero que la secuencia tenga al menos un elemento. En otras palabras, cuando es una ocurrencia excepcional que la secuencia está vacía.

Úselo FirstOrDefault()cuando sepa que tendrá que verificar si había un elemento o no. En otras palabras, cuando es legal que la secuencia esté vacía. No debe confiar en el manejo de excepciones para la verificación. (Es una mala práctica y puede afectar el rendimiento).

Finalmente, la diferencia entre First()y Take(1)es que First()devuelve el elemento en sí, mientras que Take(1)devuelve una secuencia de elementos que contiene exactamente un elemento.

driis
fuente
44
@driis: me imagino que podemos usar el mantra de la guía de excepción excepcional al elegir entre First y FirstOrDefault. Gracias por la respuesta clara.
Metro Pitufo
55
Lo único que agregaría es que si el valor predeterminado para el tipo que está seleccionando podría ser un valor válido, por ejemplo, su resultado podría ser el valor int 0, entonces manejar la excepción parece ser la mejor manera de manejar esto .
PeterBelm
25
Rasca eso, he encontrado una forma mucho más agradable de lograrlo, usa: DefaultIfEmpty (-1) .First ()
PeterBelm
55
Take no devuelve exactamente un elemento, devuelve como máximo un elemento (si especifica 1, por supuesto). También podría devolver 0 elementos, si la secuencia está inicialmente vacía.
SPIRiT_1984
3
@RoyiNamir, sí, en el contexto de la pregunta donde el parámetro a tomar es 1. También noté eso en los padres inmediatamente después de esa oración.
driis
272

.Firstlanzará una excepción cuando no haya resultados. .FirstOrDefaultno lo hará, simplemente devolverá nulo (tipos de referencia) o el valor predeterminado del tipo de valor. (por ejemplo, 0para un int.) La pregunta aquí no es cuándo desea el tipo predeterminado, sino más: ¿Está dispuesto a manejar una excepción o manejar un valor predeterminado? Dado que las excepciones deben ser excepcionales, FirstOrDefaultse prefiere cuando no está seguro de si va a obtener resultados de su consulta. Cuando lógicamente los datos deberían estar allí, se puede considerar el manejo de excepciones.

Skip() y Take() se usan normalmente al configurar la paginación en los resultados. (Como mostrar los primeros 10 resultados, y los siguientes 10 en la página siguiente, etc.)

Espero que esto ayude.

Jeroen Landheer
fuente
55
@Jeroen: buen punto sobre mejores casos de uso para usar Skip / Take.
Metro Pitufo
44
+1 para la explicación que .FirstOrDefaultdevolverá nulo para los tipos de referencia. Estaba confundido acerca de lo que sería un objeto "predeterminado". Esta respuesta aclaró eso.
Mike Taverne
115

.First()lanzará una excepción si no se devuelve ninguna fila, mientras .FirstOrDefault()que en su lugar devolverá el valor predeterminado ( NULLpara todos los tipos de referencia).

Entonces, si está preparado y dispuesto a manejar una posible excepción, .First()está bien. Si prefiere comprobar el valor de retorno de != nulltodos modos, entonces .FirstOrDefault()es su mejor opción.

Pero supongo que también es una preferencia personal. Use el que tenga más sentido para usted y se adapte mejor a su estilo de codificación.

marc_s
fuente
66

Primero()

  1. Devuelve el primer elemento de una secuencia.
  2. Lanza un error cuando no hay ningún elemento en el resultado o la fuente es nula.
  3. debe usarlo, si se espera más de un elemento y solo desea el primer elemento.

FirstOrDefault ()

  1. Devuelve el primer elemento de una secuencia o un valor predeterminado si no se encuentra ningún elemento.
  2. Lanza un error Solo si la fuente es nula.
  3. debe usarlo, si se espera más de un elemento y solo desea el primer elemento. También es bueno si el resultado está vacío.

Tenemos una tabla UserInfos, que tiene algunos registros como se muestra a continuación. Sobre la base de esta tabla a continuación, he creado un ejemplo ...

Tabla de información de usuario

Cómo usar First ()

var result = dc.UserInfos.First(x => x.ID == 1);

Solo hay un registro donde ID == 1. Debe devolver este
ID de registro : 1 Nombre: Apellido masculino: Correo electrónico de Dubey: [email protected]

var result = dc.UserInfos.First(x => x.FName == "Rahul");   

Hay varios registros donde FName == "Rahul". El primer registro debe ser devuelto.
ID: 7 Nombre: Rahul Apellido: Sharma Correo electrónico: [email protected]

var result = dc.UserInfos.First(x => x.ID ==13);

No hay registro con ID == 13. Debe producirse un error.
InvalidOperationException: la secuencia no contiene elementos

Cómo usar FirstOrDefault ()

var result = dc.UserInfos.FirstOrDefault(x => x.ID == 1);

Solo hay un registro donde ID == 1. Debe devolver este
ID de registro : 1 Nombre: Apellido masculino: Correo electrónico de Dubey: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.FName == "Rahul");

Hay varios registros donde FName == "Rahul". El primer registro debe ser devuelto.
ID: 7 Nombre: Rahul Apellido: Sharma Correo electrónico: [email protected]

var result = dc.UserInfos.FirstOrDefault(x => x.ID ==13);

No hay registro con ID == 13. El valor de retorno es nulo

Espero que te ayude a entender cuándo usar First()o FirstOrDefault().

Mukesh Kumar
fuente
44
En mi opinión, la declaración "Se debe producir un error". bajo el tercer FirstOrDefault () - el ejemplo es engañoso.
Jannik
Hola, me explican bien, pero estoy un poco confundido cuando se obtienen datos de la unión y cuando la ID no existía en una tabla de claves foráneas en ese momento, ¿cuál se usa? Actualmente, estoy usando First () pero después de leer tu respuesta no tengo idea
Por
20

En primer lugar, Takees un método completamente diferente. Devuelve un IEnumerable<T>y no uno solo T, así que eso está fuera.

Entre Firsty FirstOrDefault, debes usarFirst cuando esté seguro de que existe un elemento y si no existe, entonces hay un error.

Por cierto, si su secuencia contiene default(T)elementos (p null. Ej. ) Y necesita distinguir entre estar vacío y ser el primer elemento null, no puede usarlo FirstOrDefault.

Mehrdad Afshari
fuente
2
@Mehrdad - excelentes puntos, re: .Primero devuelve IEnumerable y cuándo no usar FirstOrDefault.
Metro Pitufo
15

Primero:

  • Devuelve el primer elemento de una secuencia.
  • Lanza excepción: no hay elementos en el resultado
  • Use when: cuando se espera más de 1 elemento y solo desea el primero

FirstOrDefault:

  • Devuelve el primer elemento de una secuencia o un valor predeterminado si no se encuentra ningún elemento
  • Lanza excepción: solo si la fuente es nula
  • Use when: cuando se espera más de 1 elemento y solo desea el primero. También está bien que el resultado esté vacío

De: http://www.technicaloverload.com/linq-single-vs-singleordefault-vs-first-vs-firstordefault/

usuario2051770
fuente
10

Otra diferencia a tener en cuenta es que si está depurando una aplicación en un entorno de Producción, es posible que no tenga acceso a los números de línea, por lo que identificar qué .First()enunciado en particular en un método arrojó la excepción puede ser difícil.

El mensaje de excepción tampoco incluirá ninguna expresión Lambda que pueda haber utilizado, lo que haría que cualquier problema sea aún más difícil de depurar.

Es por eso que siempre uso FirstOrDefault()aunque sé que una entrada nula constituiría una situación excepcional.

var customer = context.Customers.FirstOrDefault(i => i.Id == customerId);
if (customer == null)
{
   throw new Exception(string.Format("Can't find customer {0}.", customerId));
}
Kye
fuente
5

Primero()

Cuando sepa que el resultado contiene más de 1 elemento esperado y solo debería el primer elemento de secuencia.

FirstOrDefault ()

FirstOrDefault () es igual que First () excepto que, si ningún elemento coincide con la condición especificada, devuelve el valor predeterminado del tipo subyacente de colección genérica. No arroja InvalidOperationException si no se encuentra ningún elemento. Pero la colección de elementos o una secuencia es nula de lo que arroja una excepción.

Nimesh khatri
fuente
Hola, me explican bien, pero estoy un poco confundido cuando se obtienen datos de la unión y cuando la ID no existía en una tabla de claves foráneas en ese momento, ¿cuál se usa? Actualmente, estoy usando First () pero después de leer tu respuesta no tengo idea
Por
4

Este tipo de función pertenece a operadores de elementos. Algunos operadores de elementos útiles se definen a continuación.

  1. Primero / PrimeroOr Predeterminado
  2. Last / LastOrDefault
  3. Single / SingleOrDefault

Usamos operadores de elementos cuando necesitamos seleccionar un solo elemento de una secuencia basada en una determinada condición. Aquí hay un ejemplo.

  List<int> items = new List<int>() { 8, 5, 2, 4, 2, 6, 9, 2, 10 };

El operador First () devuelve el primer elemento de una secuencia después de cumplir la condición. Si no se encuentra ningún elemento, arrojará una excepción.

int result = items.Where (item => item == 2) .Primero ();

El operador FirstOrDefault () devuelve el primer elemento de una secuencia después de cumplir la condición. Si no se encuentra ningún elemento, devolverá el valor predeterminado de ese tipo.

int result1 = items.Where (item => item == 2) .FirstOrDefault ();

Sheo Dayal Singh
fuente
Bien explicado con un ejemplo fácil de entender.
Arslan Bhatti
3

Encontré un sitio web que parece explicar la necesidad de FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
Si no hay resultados para una consulta y desea llamar a First () o Single () para obtener una sola fila ... Obtendrá una excepción "La secuencia no contiene elementos".

Descargo de responsabilidad: nunca he usado LINQ, así que disculpe si esto está fuera de lugar.

NULO
fuente
2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

¿Cuál usar? Debe decidirse por la lógica del negocio, y no por el miedo a la excepción / falla del programa.

Por ejemplo, si la lógica de negocios dice que no podemos tener cero transacciones en ningún día hábil (solo asuma). Entonces no deberías tratar de manejar este escenario con alguna programación inteligente. Siempre usaré First () sobre dicha colección, y dejaré que el programa falle si algo más arruinó la lógica de negocios.

Código:

var transactionsOnWorkingDay = GetTransactionOnLatestWorkingDay();
var justNeedOneToProcess = transactionsOnWorkingDay.First(): //Not FirstOrDefault()

Me gustaría ver otros comentarios sobre esto.

Manish Basantani
fuente
El valor predeterminado para los tipos de referencia y anulables es nulo.
dsa
Fallar rápidamente es bueno; sin embargo, para el escenario que describió, prefiero ver Primero, hacer que falle, detectar la excepción y luego devolver un error significativo. Like catch (InvalidOperationException e) {lanzar una nueva InvalidOperationException ("¡No puede haber cero transacciones en un día!", E)}; Pero sí, usar el valor predeterminado para evitar enfrentar un problema real de lógica de negocios es muy malo.
Mathieson
1

Ok déjame dar mis dos centavos. First / Firstordefault son para cuando usa el segundo constructor. No explicaré lo que es, pero es cuando potencialmente siempre usarías uno porque no quieres causar una excepción.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));
arriano
fuente
No exactamente. El primer constructor se usa ampliamente cuando necesita recuperar solo un elemento o debe evitar un error de compilación al asignar el resultado a un valor que no es una matriz y está seguro de que la consulta devuelve exactamente un resultado. Si bien puede parecer más rápido usar el segundo constructor en lugar de usar un .Where () adicional (porque cree que LINQ deja de evaluar los elementos de la lista después de encontrar el primero), siempre se detiene en el primer elemento
usr-local-ΕΨΗΕΛΩΝ
0

Otros han descrito muy bien la diferencia entre First()y FirstOrDefault(). Quiero dar un paso más en la interpretación de la semántica de estos métodos. En mi opinión FirstOrDefaultse está usando demasiado. En la mayoría de los casos, cuando está filtrando datos, esperaría recuperar una colección de elementos que coinciden con la condición lógica o un único elemento único por su identificador único, como un usuario, libro, publicación, etc. por qué incluso podemos llegar a decir que FirstOrDefault()es un olor a código, no porque haya algo mal, sino porque se está usando con demasiada frecuencia. Esta publicación de blog explora el tema en detalle. OMI la mayoría de las vecesSingleOrDefault() es una alternativa mucho mejor, así que tenga cuidado con este error y asegúrese de utilizar el método más apropiado que represente claramente su contrato y sus expectativas.

Vasil Kosturski
fuente
-6

Hay muchas formas de implementar consultas simples y simples en colecciones, solo escribimos uniones en sql, un filtro se puede aplicar primero o último dependiendo de la necesidad y la necesidad.

Aquí hay un ejemplo donde podemos encontrar un elemento con una identificación en una colección. Para agregar más sobre esto, los métodos Primero, FirstOrDefaultidealmente devolverían lo mismo cuando una colección tiene al menos un registro. Sin embargo, si una colección está bien estar vacía. luego Firstdevolverá una excepción pero FirstOrDefaultvolverá nullo será predeterminada. Por ejemplo, intdevolverá 0. Por lo tanto, el uso de tales se dice que es una preferencia personal, pero es mejor usarlo FirstOrDefaultpara evitar el manejo de excepciones. Aquí hay un ejemplo donde, ejecutamos una colección de lista de transacciones

Venkat
fuente