Quand utiliser .First et quand utiliser .FirstOrDefault avec LINQ?

824

J'ai cherché et n'ai pas vraiment trouvé de réponse claire quant au moment où vous souhaitez utiliser .Firstet quand vous souhaitez utiliser .FirstOrDefaultavec LINQ.

  • Quand voudriez-vous l'utiliser .First? Uniquement lorsque vous souhaitez intercepter l'exception si aucun résultat n'est renvoyé?

    var result = List.Where(x => x == "foo").First();
  • Et quand voudriez-vous l'utiliser .FirstOrDefault? Quand vous voudriez toujours le type par défaut si aucun résultat?

    var result = List.Where(x => x == "foo").FirstOrDefault();
  • Et d'ailleurs, qu'en est-il de Take?

    var result = List.Where(x => x == "foo").Take(1);
Metro Schtroumpf
la source
86
.Firstet les .FirstOrDefaultdeux prennent des prédicats comme arguments, donc var result = List.Where(x => x == "foo").First();pourraient être réécrits commevar result = List.First(x => x == "foo");
Rian Schmits
59
N'oubliez pas de considérer Singleet SingleOrDefault. Je déteste quand les gens utilisent Firstquand ils veulent vraiment dire Single; )
BartoszKP
19
Single ou SingleOrDefault lèverait une exception s'il y a plus d'un élément retourné! Je pense que FirstOrDefault est meilleur dans la plupart des cas!
Eric Draven
21
Le fait est que lorsque vous attendez un résultat unique, vous devez le dire, et l'exception indique que votre logique a échoué.
NetMage
1
Considérez également que l'utilisation .FirstOrDefault()vous donne toujours la possibilité de lever une exception plus significative. Si une exception de séquence est levée et plusieurs .First()dans une méthode, il peut être difficile de discerner quelle instruction est le problème.
StingyJack du

Réponses:

807

J'utiliserais First()quand je connais ou que je m'attends à ce que la séquence ait au moins un élément. En d'autres termes, lorsque c'est une occurrence exceptionnelle que la séquence est vide.

À utiliser FirstOrDefault()lorsque vous savez que vous devrez vérifier s'il y a un élément ou non. En d'autres termes, quand il est légal que la séquence soit vide. Vous ne devez pas vous fier à la gestion des exceptions pour la vérification. (C'est une mauvaise pratique et peut nuire aux performances).

Enfin, la différence entre First()et Take(1)est que First()renvoie l'élément lui-même, tandis que Take(1)renvoie une séquence d'éléments qui contient exactement un élément.

driis
la source
4
@driis - J'imagine que nous pouvons utiliser le mantra de la directive d'exception exceptionnelle lors du choix entre First et FirstOrDefault. Merci pour la réponse claire.
Metro Smurf
5
La seule chose que j'ajouterais, c'est que si la valeur par défaut du type que vous sélectionnez peut être une valeur valide, par exemple, votre résultat pourrait être la valeur int 0, alors la gestion de l'exception semble être la meilleure façon de gérer cela. .
PeterBelm
25
Grattez cela, j'ai trouvé une manière beaucoup plus agréable d'accomplir cela, utilisez: DefaultIfEmpty (-1) .First ()
PeterBelm
5
Take ne renvoie pas exactement un élément, il renvoie au plus un élément (si vous spécifiez 1, bien sûr). Il pourrait aussi bien retourner 0 élément, si la séquence est initialement vide.
SPIRiT_1984
3
@RoyiNamir, oui dans le contexte de la question où le paramètre à prendre est 1. J'ai également noté cela en parens immédiatement après cette phrase.
driis
272

.Firstlèvera une exception lorsqu'il n'y a aucun résultat. .FirstOrDefaultne le fera pas, il retournera simplement null (types de référence) ou la valeur par défaut du type de valeur. (par exemple comme 0pour un int.) La question ici n'est pas quand vous voulez le type par défaut, mais plus: Êtes-vous prêt à gérer une exception ou à gérer une valeur par défaut? Étant donné que les exceptions doivent être exceptionnelles, il FirstOrDefaultest préférable de ne pas être sûr d'obtenir des résultats de votre requête. Lorsque, logiquement, les données doivent être présentes, la gestion des exceptions peut être envisagée.

Skip()et Take()sont normalement utilisés lors de la configuration de la pagination dans les résultats. (Comme afficher les 10 premiers résultats et les 10 suivants sur la page suivante, etc.)

J'espère que cela t'aides.

Jeroen Landheer
la source
5
@Jeroen - bon point sur de meilleurs cas d'utilisation pour l'utilisation de Skip / Take.
Metro Smurf
4
+1 pour l'explication qui .FirstOrDefaultrenverra null pour les types de référence. J'étais confus quant à ce que serait un objet "par défaut". Cette réponse a clarifié cela.
Mike Taverne
115

.First()générera une exception s'il n'y a pas de ligne à renvoyer, tandis que .FirstOrDefault()retournera la valeur par défaut ( NULLpour tous les types de référence) à la place.

Donc, si vous êtes prêt et disposé à gérer une éventuelle exception, ça .First()va. Si vous préférez != nullquand même vérifier la valeur de retour , .FirstOrDefault()c'est votre meilleur choix.

Mais je suppose que c'est aussi une préférence personnelle. Utilisez celui qui vous convient le mieux et correspond mieux à votre style de codage.

marc_s
la source
66

Première()

  1. Renvoie le premier élément d'une séquence.
  2. Il renvoie une erreur lorsqu'il n'y a aucun élément dans le résultat ou que la source est nulle.
  3. vous devez l'utiliser, si plusieurs éléments sont attendus et que vous ne souhaitez que le premier élément.

FirstOrDefault ()

  1. Renvoie le premier élément d'une séquence ou une valeur par défaut si aucun élément n'est trouvé.
  2. Il renvoie une erreur uniquement si la source est nulle.
  3. vous devez l'utiliser, si plusieurs éléments sont attendus et que vous ne souhaitez que le premier élément. Aussi bon si le résultat est vide.

Nous avons une table UserInfos, qui a quelques enregistrements comme indiqué ci-dessous. Sur la base de ce tableau ci-dessous, j'ai créé un exemple ...

Table UserInfo

Comment utiliser First ()

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

Il n'y a qu'un seul enregistrement où ID == 1. Doit renvoyer cet enregistrement
ID: 1 Prénom: Manish Nom de famille: Dubey Courriel: [email protected]

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

Il existe plusieurs enregistrements où FName == "Rahul". Le premier enregistrement doit être de retour.
ID: 7 Prénom: Rahul Nom: Sharma Courriel: [email protected]

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

Il n'y a aucun enregistrement avec l'ID == 13. Une erreur doit se produire.
InvalidOperationException: la séquence ne contient aucun élément

Comment utiliser FirstOrDefault ()

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

Il n'y a qu'un seul enregistrement où ID == 1. Doit renvoyer cet enregistrement
ID: 1 Prénom: Manish Nom de famille: Dubey Courriel: [email protected]

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

Il existe plusieurs enregistrements où FName == "Rahul". Le premier enregistrement doit être de retour.
ID: 7 Prénom: Rahul Nom: Sharma Courriel: [email protected]

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

Il n'y a pas d'enregistrement avec l'ID == 13. La valeur de retour est nulle

J'espère que cela vous aidera à comprendre quand utiliser First()ou FirstOrDefault().

Mukesh Kumar
la source
4
À mon avis, la déclaration "Une erreur devrait se produire." sous le troisième FirstOrDefault () - l'exemple est trompeur.
Jannik
Bonjour, vous expliquez bien, mais je suis un peu confus quand est-ce que get data from join et quand ID n'existait pas dans une table de clé étrangère à ce moment-là lequel est utilisé? Actuellement, j'utilise First () mais après avoir lu votre réponse, je n'ai aucune idée.Veuillez aider
Brijesh Mavani
20

Tout d'abord, Takec'est une méthode complètement différente. Il renvoie un IEnumerable<T>et pas un seul T, donc c'est sorti.

Entre Firstet FirstOrDefault, vous devez utiliser Firstlorsque vous êtes sûr qu'un élément existe et si ce n'est pas le cas, il y a une erreur.

Soit dit en passant, si votre séquence contient des default(T)éléments (par exemple null) et que vous devez faire la distinction entre être vide et le premier élément étant null, vous ne pouvez pas utiliser FirstOrDefault.

Mehrdad Afshari
la source
2
@Mehrdad - grands points, re: .First renvoie IEnumerable et quand ne pas utiliser FirstOrDefault.
Metro Smurf
15

Première:

  • Renvoie le premier élément d'une séquence
  • Lance une exception: il n'y a aucun élément dans le résultat
  • Utiliser quand: lorsque plus d'un élément est attendu et que vous ne souhaitez que le premier

FirstOrDefault:

  • Renvoie le premier élément d'une séquence ou une valeur par défaut si aucun élément n'est trouvé
  • Lève une exception: uniquement si la source est nulle
  • Utiliser quand: lorsque plus d'un élément est attendu et que vous ne souhaitez que le premier. De plus, il est acceptable que le résultat soit vide

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

user2051770
la source
10

Une autre différence à noter est que si vous déboguez une application dans un environnement de production, vous n'aurez peut-être pas accès aux numéros de ligne, il .First()peut donc être difficile d' identifier quelle instruction particulière dans une méthode a levé l'exception.

Le message d'exception n'inclura pas non plus d'expressions Lambda que vous auriez pu utiliser, ce qui rendrait tout problème encore plus difficile à déboguer.

C'est pourquoi j'utilise toujours FirstOrDefault()même si je sais qu'une entrée nulle constituerait une situation exceptionnelle.

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

Première()

Lorsque vous savez que le résultat contient plus d'un élément attendu et que vous ne devez que le premier élément de la séquence.

FirstOrDefault ()

FirstOrDefault () est similaire à First () sauf que, si aucun élément ne correspond à la condition spécifiée, il renvoie la valeur par défaut du type sous-jacent de collection générique. Il ne lève pas InvalidOperationException si aucun élément n'a été trouvé. Mais la collection d'un élément ou d'une séquence est nulle car elle lève une exception.

Nimesh khatri
la source
Bonjour, vous expliquez bien, mais je suis un peu confus quand est-ce que get data from join et quand ID n'existait pas dans une table de clé étrangère à ce moment-là lequel est utilisé? Actuellement, j'utilise First () mais après avoir lu votre réponse, je n'ai aucune idée.Veuillez aider
Brijesh Mavani
4

Ce type de fonction appartient aux opérateurs d'éléments. Certains opérateurs d'éléments utiles sont définis ci-dessous.

  1. First / FirstOrDefault
  2. Last / LastOrDefault
  3. Single / SingleOrDefault

Nous utilisons des opérateurs d'éléments lorsque nous devons sélectionner un seul élément dans une séquence en fonction d'une certaine condition. Voici un exemple.

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

L'opérateur First () renvoie le premier élément d'une séquence après avoir satisfait à la condition. Si aucun élément n'est trouvé, il lèvera une exception.

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

L'opérateur FirstOrDefault () renvoie le premier élément d'une séquence après avoir satisfait à la condition. Si aucun élément n'est trouvé, il retournera la valeur par défaut de ce type.

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

Sheo Dayal Singh
la source
joliment expliqué avec un exemple facile à comprendre.
Arslan Bhatti
3

J'ai trouvé un site Web qui apparait pour expliquer la nécessité de FirstOrDefault
http://thepursuitofalife.com/the-linq-firstordefault-method-and-null-resultsets/
S'il n'y a aucun résultat à une requête et que vous souhaitez appeler d'abord () ou Single () pour obtenir une seule ligne ... Vous obtiendrez une exception "La séquence ne contient aucun élément".

Avis de non-responsabilité: Je n'ai jamais utilisé LINQ, donc mes excuses si c'est loin de la marque.

NUL
la source
2
someList.First(); // exception if collection is empty.
someList.FirstOrDefault(); // first item or default(Type)

Lequel utiliser? Elle doit être décidée par la logique métier, et non par la crainte d'une défaillance d'exception / programme.

Par exemple, si la logique métier dit que nous ne pouvons avoir aucune transaction aucun jour ouvrable (supposons simplement). Ensuite, vous ne devriez pas essayer de gérer ce scénario avec une programmation intelligente. J'utiliserai toujours First () sur une telle collection et laisserai le programme échouer si quelque chose d'autre a foiré la logique métier.

Code:

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

J'aimerais voir d'autres commentaires à ce sujet.

Manish Basantani
la source
La valeur par défaut pour les types référence et nullable est null.
dsa
Un échec rapide est une bonne chose - cependant pour le scénario que vous avez décrit, je préfère voir d'abord, le faire échouer, intercepter l'exception, puis retourner une erreur significative. Comme catch (InvalidOperationException e) {lever une nouvelle InvalidOperationException ("Impossible d'avoir zéro transaction en un jour!", E)}; Mais oui, utiliser la valeur par défaut pour éviter de traiter un vrai problème de logique métier est très mauvais.
Mathieson
1

Ok, laissez-moi donner mes deux cents. First / Firstordefault sont pour quand vous utilisez le deuxième constructeur. Je n'expliquerai pas ce que c'est, mais c'est quand vous pourriez potentiellement toujours en utiliser un parce que vous ne voulez pas provoquer d'exception.

person = tmp.FirstOrDefault(new Func<Person, bool>((p) =>
{
    return string.IsNullOrEmpty(p.Relationship);
}));
Arian
la source
Pas exactement. Le premier constructeur est largement utilisé lorsque vous devez récupérer un seul élément ou devez éviter une erreur de compilation lors de l'affectation du résultat à une valeur qui n'est pas un tableau et vous êtes sûr que la requête renvoie exactement un résultat. Bien qu'il puisse sembler plus rapide d'utiliser le deuxième constructeur plutôt que d'utiliser un .Where () supplémentaire (car vous pensez que LINQ arrête d'évaluer les éléments de la liste après avoir trouvé le premier), il s'arrête toujours au premier élément
usr-local-ΕΨΗΕΛΩΝ
0

D'autres ont très bien décrit la différence entre First()et FirstOrDefault(). Je veux franchir une étape supplémentaire dans l'interprétation de la sémantique de ces méthodes. À mon avis, FirstOrDefaultest beaucoup surutilisé. Dans la majorité des cas, lorsque vous filtrez des données, vous vous attendez à récupérer une collection d'éléments correspondant à la condition logique ou un seul élément unique par son identifiant unique - tel qu'un utilisateur, un livre, une publication, etc. pourquoi nous pouvons même aller jusqu'à dire que FirstOrDefault()c'est une odeur de code non pas parce qu'il y a quelque chose qui ne va pas mais parce qu'il est utilisé trop souvent. Ce billet de blog explore le sujet en détail. OMI la plupart du tempsSingleOrDefault() est une bien meilleure alternative, alors faites attention à cette erreur et assurez-vous d'utiliser la méthode la plus appropriée qui représente clairement votre contrat et vos attentes.

Vasil Kosturski
la source
-6

linq de nombreuses façons d'implémenter une simple requête simple sur des collections, il suffit d'écrire des jointures en sql, un filtre peut être appliqué en premier ou en dernier selon le besoin et la nécessité.

Voici un exemple où nous pouvons trouver un élément avec un id dans une collection. Pour en ajouter plus, les méthodes First FirstOrDefault,, devraient idéalement renvoyer la même chose lorsqu'une collection a au moins un enregistrement. Si, cependant, une collection peut être vide. puis Firstretournera une exception mais FirstOrDefaultreviendra nullou par défaut. Par exemple, intretournera 0. Ainsi, l'utilisation de tels est bien que considérée comme une préférence personnelle, mais il vaut mieux l'utiliser FirstOrDefaultpour éviter la gestion des exceptions. voici un exemple où, nous parcourons une collection de transactionlist

venkat
la source