web-dev-qa-db-fra.com

Les fonctions doivent-elles renvoyer null ou un objet vide?

Quelle est la meilleure pratique lors du renvoi de données depuis des fonctions. Est-il préférable de retourner un objet Null ou un objet vide? Et pourquoi devrait-on faire l'un sur l'autre?

Considère ceci:

public UserEntity GetUserById(Guid userId)
{
     //Imagine some code here to access database.....

     //Check if data was returned and return a null if none found
     if (!DataExists)
        return null; 
        //Should I be doing this here instead? 
        //return new UserEntity();  
     else
        return existingUserEntity;
}

Supposons qu'il y ait des cas valides dans ce programme selon lesquels il n'y aurait aucune information d'utilisateur dans la base de données avec ce GUID. J'imagine qu'il ne serait pas approprié de lancer une exception dans ce cas ?? De plus, j'ai l'impression que la gestion des exceptions peut nuire aux performances.

210
7wp

Renvoyer une valeur nulle est généralement la meilleure idée si vous souhaitez indiquer qu'aucune donnée n'est disponible.

Un objet vide implique que des données ont été renvoyées, alors que renvoyer null indique clairement que rien n'a été renvoyé.

De plus, renvoyer une valeur null entraînera une exception null si vous tentez d'accéder aux membres de l'objet, ce qui peut être utile pour mettre en évidence un code erroné - tenter d'accéder à un membre dépourvu de sens n'a aucun sens. L'accès aux membres d'un objet vide n'échouera pas, ce qui signifie que les bogues peuvent rester non découverts.

208
ljs

Cela dépend de ce qui a le plus de sens pour votre cas.

Est-il judicieux de renvoyer null, par exemple "aucun tel utilisateur n'existe"?

Ou est-il judicieux de créer un utilisateur par défaut? Cela semble tout à fait logique lorsque vous pouvez supposer en toute sécurité que si un utilisateur N'EXISTE PAS, le code appelant a l'intention de le faire exister lorsqu'il le demande.

Ou est-il judicieux de lancer une exception (à la "FileNotFound") si le code appelant demande un utilisateur avec un identifiant invalide?

Cependant - du point de vue de la séparation des préoccupations et de la SRP, les deux premiers sont plus corrects. Et techniquement , le premier est le plus correct (mais seulement par un cheveu) - GetUserById ne devrait être tenu responsable que d'une chose: obtenir l'utilisateur. Traiter son propre cas "utilisateur n'existe pas" en renvoyant quelque chose d'autre pourrait être une violation de SRP. Séparer en une vérification différente - bool DoesUserExist(id) serait approprié si vous choisissez de lever une exception.

Basé sur les commentaires détaillés ci-dessous: s'il s'agit d'une question de conception au niveau de l'API, cette méthode pourrait être analogue à "OpenFile" ou "ReadEntireFile". Nous "ouvrons" un utilisateur d'un dépôt et hydratons l'objet à partir des données résultantes. Une exception pourrait être appropriée dans ce cas. Ce n'est peut-être pas, mais ça pourrait l'être.

Toutes les approches sont acceptables - cela dépend, tout simplement, du contexte plus large de l’API/de l’application.

44
Rex M

Personnellement, j'utilise NULL. Il est clair qu'il n'y a pas de données à renvoyer. Mais il existe des cas où un Null Object peut être utile.

30
Fernando

Si votre type de retour est un tableau, retournez un tableau vide, sinon, retournez null.

27
Darin Dimitrov

Vous devriez lancer une exception (uniquement) si un contrat spécifique est rompu.
Dans votre exemple spécifique, demandant une UserEntity basée sur un ID connu, cela dépend du fait que les utilisateurs manquants (supprimés) constituent un cas attendu. Si c'est le cas, alors retournez null, mais s'il ne s'agit pas d'un cas attendu, émettez une exception.
Notez que si la fonction s'appelait UserEntity GetUserByName(string name), elle ne lancerait probablement pas, mais renverrait null. Dans les deux cas, renvoyer une UserEntity vide serait inutile.

Pour les chaînes, les tableaux et les collections, la situation est généralement différente. Je me souviens de quelques directives MS indiquant que les méthodes devraient accepter null comme une liste 'vide' mais renvoyer des collections de longueur nulle plutôt que null. La même chose pour les chaînes. Notez que vous pouvez déclarer des tableaux vides: int[] arr = new int[0];

12
Henk Holterman

Il s'agit d'une question commerciale, selon que l'existence d'un utilisateur avec un identifiant de guidage spécifique est un cas d'utilisation normal prévu pour cette fonction ou s'il s'agit d'une anomalie empêchant l'application de mener à bien la fonction que cette méthode fournit à l'utilisateur. objet à ...

S'il s'agit d'une "exception", en ce sens que l'absence d'un utilisateur avec cet ID empêchera l'application de mener à bien n'importe quelle fonction, (Nous allons créer une facture pour un client auquel nous avons expédié le produit ... ), alors cette situation devrait générer une ArgumentException (ou une autre exception personnalisée).

Si un utilisateur manquant est ok, (l'un des résultats normaux potentiels de l'appel de cette fonction), retournez une valeur null ....

EDIT: (pour répondre au commentaire d'Adam dans une autre réponse)

Si l'application contient plusieurs processus métier, dont un ou plusieurs requièrent la réussite d'un utilisateur et l'un ou plusieurs d'entre eux qui peuvent se terminer avec succès sans utilisateur, l'exception doit être renvoyée plus loin dans la pile d'appels, plus près de l'endroit où elle se trouve. les processus métier qui nécessitent un utilisateur appellent ce fil d'exécution. Les méthodes entre cette méthode et ce point (où l'exception est levée) doivent simplement indiquer qu'aucun utilisateur n'existe (null, boolean, peu importe, il s'agit d'un détail d'implémentation).

Mais si tous les processus de l'application obligent un utilisateur, je lirais encore l'exception dans cette méthode ...

11
Charles Bretana

Personnellement, je renverrais null, car c’est ce que je voudrais que la couche DAL/Repository agisse.

S'il n'existe pas, ne retournez rien qui puisse être interprété comme une opération d'extraction d'objet réussie, null fonctionne à merveille ici.

Le plus important est d’être cohérent sur votre couche DAL/Repos, afin de ne pas vous tromper quant à son utilisation.

10
Alex Moore

J'ai tendance à

  • return null _ si l’identifiant d’objet n’existe pas alors que l’on ne sait pas au préalable s’il devrait exister.
  • throw si l'ID d'objet n'existe pas alors qu'il devrait exister.

Je différencie ces deux scénarios avec ces trois types de méthodes. Première:

Boolean TryGetSomeObjectById(Int32 id, out SomeObject o)
{
    if (InternalIdExists(id))
    {
        o = InternalGetSomeObject(id);

        return true;
    }
    else
    {
        return false;
    }
}

Seconde:

SomeObject FindSomeObjectById(Int32 id)
{
    SomeObject o;

    return TryGetObjectById(id, out o) ? o : null;
}

Troisième:

SomeObject GetSomeObjectById(Int32 id)
{
    SomeObject o;

    if (!TryGetObjectById(id, out o))
    {
        throw new SomeAppropriateException();
    }

    return o;
}
7
Johann Gerell

Une autre approche consiste à transmettre un objet de rappel ou un délégué qui agira sur la valeur. Si aucune valeur n'est trouvée, le rappel n'est pas appelé.

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
}

Cela fonctionne bien lorsque vous souhaitez éviter les contrôles nuls sur l'ensemble de votre code et lorsque le fait de ne pas trouver une valeur n'est pas une erreur. Vous pouvez également fournir un rappel lorsque aucun objet n'est trouvé si vous avez besoin d'un traitement spécial.

public void GetUserById(Guid id, UserCallback callback, NotFoundCallback notFound)
{
    // Lookup user
    if (userFound)
        callback(userEntity);  // or callback.Call(userEntity);
    else
        notFound(); // or notFound.Call();
}

La même approche utilisant un seul objet pourrait ressembler à ceci:

public void GetUserById(Guid id, UserCallback callback)
{
    // Lookup user
    if (userFound)
        callback.Found(userEntity);
    else
        callback.NotFound();
}

Du point de vue de la conception, j'aime beaucoup cette approche, mais elle a l’inconvénient de rendre le site d’appel plus volumineux dans des langues qui ne prennent pas facilement en charge les fonctions de première classe.

6
Marc

Je préfère null, car il est compatible avec l'opérateur null-coalescing (??).

4
Andrew Medico

Je dirais que retourne null au lieu d'un objet vide.

Mais l'instance spécifique que vous avez mentionnée ici, vous recherchez un utilisateur par identifiant d'utilisateur, qui est en quelque sorte la clé de cet utilisateur. Dans ce cas, je souhaiterais probablement lever une exception si aucune instance d'utilisateur n'est trouvée. .

C'est la règle que je suis généralement suivre:

  • Si aucun résultat n'a été trouvé lors d'une opération de recherche par clé primaire, déclenchez ObjectNotFoundException.
  • Si aucun résultat trouvé sur une recherche par aucun autre critère, retourne null.
  • Si aucun résultat trouvé sur une recherche par un critère non clé pouvant renvoyer plusieurs objets, une collection vide est renvoyée.
4
Partha Choudhury

Nous utilisons CSLA.NET et nous pensons qu’une extraction de données ayant échoué devrait renvoyer un objet "vide". C’est en fait assez ennuyeux, car cela exige la convention de vérifier si obj.IsNew plutôt que obj == null.

Comme mentionné dans une précédente affiche, Les valeurs nulles et renvoyées entraîneront l’échec immédiat du code, ce qui réduira les risques de furtivité causés par des objets vides.

Personnellement, je pense que null est plus élégant.

C'est un cas très courant, et je suis surpris que les gens ici semblent surpris: dans toute application Web, les données sont extraites à l'aide d'un paramètre de chaîne de requête, qui peut évidemment être mutilé, ce qui oblige le développeur à gérer les incidents "introuvable". ".

Vous pouvez gérer cela en:

 if (User.Exists (id)) {
 this.User = User.Fetch (id); 
} else {
 Response.Redirect ("~ /notfound.aspx");
Buch

... mais c'est un appel supplémentaire à la base de données à chaque fois, ce qui peut poser problème sur les pages à fort trafic. Tandis que:

 this.User = User.Fetch (id); 
 
 if (this.User == null) {
 Response.Redirect ("~/notfound. aspx "); 
} 

... nécessite un seul appel.

4
Keith Williams

Cela variera en fonction du contexte, mais je renverrai généralement null si je recherche un objet particulier (comme dans votre exemple) et une collection vide si je cherche un ensemble d'objets mais il n'y en a pas.

Si vous avez commis une erreur dans votre code et renvoyé null conduit à des exceptions de pointeur null, le plus tôt vous le détecterez, mieux ce sera. Si vous retournez un objet vide, son utilisation initiale peut fonctionner, mais des erreurs risquent de se produire ultérieurement.

3
Jacob Mattison

Les meilleurs dans ce cas renvoient "null" dans un cas où il n'y a pas un tel utilisateur. Également rendre votre méthode statique.

Modifier:

Généralement, les méthodes de ce type appartiennent à une classe "User" et n'ont pas d'accès à ses membres d'instance. Dans ce cas, la méthode doit être statique, sinon vous devez créer une instance de "User", puis appeler la méthode GetUserById qui renverra une autre instance "User". D'accord, c'est déroutant. Mais si la méthode GetUserById est membre d’une classe "DatabaseFactory", vous n’aurez aucun problème à la laisser en tant que membre d’instance.

3
Kamarey

Je suis un étudiant français en informatique, alors excusez mon anglais médiocre. Dans nos classes, on nous dit qu'une telle méthode ne devrait jamais renvoyer null, ni un objet vide. L'utilisateur de cette méthode est censé d'abord vérifier que l'objet qu'il recherche existe avant d'essayer de l'obtenir.

En utilisant Java, il nous est demandé d’ajouter une assert exists(object) : "You shouldn't try to access an object that doesn't exist"; au début de toute méthode pouvant renvoyer null, pour exprimer la "précondition" (je ne sais pas quel est le mot en anglais).

IMO, ce n’est vraiment pas facile à utiliser mais c’est ce que j’utilise, attendre quelque chose de mieux.

3
Saend

Si le cas de l'utilisateur introuvable ne se présente pas assez souvent et que vous souhaitez traiter ce problème de différentes manières (en lançant parfois une exception, en remplaçant parfois un utilisateur vide), vous pouvez également utiliser un paramètre proche de Option ou le type Maybe de Haskell, qui sépare explicitement la casse "aucune valeur" de "a trouvé quelque chose!". Le code d'accès à la base de données pourrait ressembler à ceci:

public Option<UserEntity> GetUserById(Guid userId)
{
 //Imagine some code here to access database.....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return Option<UserEntity>.Nothing; 
 else
    return Option.Just(existingUserEntity);
}

Et être utilisé comme ceci:

Option<UserEntity> result = GetUserById(...);
if (result.IsNothing()) {
    // deal with it
} else {
    UserEntity value = result.GetValue();
}

Malheureusement, tout le monde semble rouler un type comme celui-ci.

3
yatima2975

Dans notre Business Objects, nous avons 2 méthodes Get principales:

Pour garder les choses simples dans le contexte ou vous interrogez ils seraient:

// Returns null if user does not exist
public UserEntity GetUserById(Guid userId)
{
}

// Returns a New User if user does not exist
public UserEntity GetNewOrExistingUserById(Guid userId)
{
}

La première méthode est utilisée lors de l'obtention d'entités spécifiques, la seconde est utilisée spécifiquement lors de l'ajout ou de la modification d'entités sur des pages Web.

Cela nous permet d’avoir le meilleur des deux mondes dans le contexte où ils sont utilisés.

3
Mark Redman

Personnellement, je retourne une instance par défaut de l'objet. La raison en est que je m'attends à ce que la méthode renvoie zéro à plusieurs ou zéro à un (en fonction de l'objectif de la méthode). En utilisant cette approche, la seule raison pour laquelle ce serait un état d'erreur de quelque nature que ce soit est que si la méthode ne renvoie aucun objet et était toujours attendue (en termes de retour un à plusieurs ou singulier).

En ce qui concerne l'hypothèse selon laquelle il s'agit d'une question de domaine commercial, je ne la vois tout simplement pas de ce côté de l'équation. La normalisation des types de retour est une question valide d'architecture d'application. À tout le moins, il est sujet à la normalisation des pratiques de codage. Je doute qu'il y ait un utilisateur professionnel qui va dire "dans le scénario X, donnez-leur simplement la valeur null".

3
Joseph Ferris

Je retourne généralement null. Il fournit un mécanisme simple et rapide pour détecter si quelque chose est foiré sans faire exception et en utilisant des tonnes d'essais/captures partout.

2
whatsisname

Question intéressante et je pense qu'il n'y a pas de "bonne" réponse, car cela dépend toujours de la responsabilité de votre code. Votre méthode sait-elle si aucune donnée trouvée est un problème ou non? Dans la plupart des cas, la réponse est "non" et c'est pourquoi, si vous renvoyez la valeur null et laissez l'appelant gérer la situation, la situation est parfaite.

Peut-être une bonne approche pour distinguer les méthodes de projection des méthodes de renvoi nul consiste à trouver une convention dans votre équipe: les méthodes qui disent "obtenir" quelque chose devraient renvoyer une exception s'il n'y a rien à obtenir. Les méthodes susceptibles de renvoyer null pourraient être nommées différemment, par exemple, "Rechercher ...".

2
Marc Wittke

Pour les types de collection, je renverrais une collection vide. Pour tous les autres types, je préfère utiliser les modèles NullObject pour renvoyer un objet qui implémente la même interface que celle du type renvoyé. pour plus de détails sur la vérification du motif texte du lien

En utilisant le modèle NullObject, ceci serait: -

public UserEntity GetUserById(Guid userId)

{// Imaginez du code ici pour accéder à la base de données .....

 //Check if data was returned and return a null if none found
 if (!DataExists)
    return new NullUserEntity(); //Should I be doing this here instead? return new UserEntity();  
 else
    return existingUserEntity;

}

class NullUserEntity: IUserEntity { public string getFirstName(){ return ""; } ...} 
2
vikram nayak

Pardonnez mon pseudo-php/code.

Je pense que cela dépend vraiment de l'utilisation prévue du résultat.

Si vous avez l'intention de modifier/modifier la valeur de retour et de la sauvegarder, renvoyez un objet vide. De cette façon, vous pouvez utiliser la même fonction pour renseigner des données sur un objet nouveau ou existant.

Supposons que j'ai une fonction qui prend une clé primaire et un tableau de données, remplit la ligne avec des données, puis enregistre l'enregistrement résultant dans la base de données. Puisque j'ai l'intention de remplir l'objet avec mes données de toute façon, cela peut être un énorme avantage de récupérer un objet vide de la part du getter. De cette façon, je peux effectuer des opérations identiques dans les deux cas. Vous utilisez le résultat de la fonction getter, peu importe quoi.

Exemple:

function saveTheRow($prim_key, $data) {
    $row = getRowByPrimKey($prim_key);

    // Populate the data here

    $row->save();
}

Nous pouvons voir ici que la même série d'opérations manipule tous les enregistrements de ce type.

Cependant, si le but ultime de la valeur de retour est de lire et de faire quelque chose avec les données, je renverrais alors null. De cette façon, je peux très rapidement déterminer si aucune donnée n'a été renvoyée et afficher le message approprié à l'utilisateur.

Généralement, je récupère les exceptions dans ma fonction qui récupère les données (afin que je puisse consigner les messages d'erreur, etc.), puis renvoie null directement à partir de la capture. En général, quel que soit le problème rencontré par l’utilisateur final, je trouve donc préférable d’encapsuler mon enregistrement/traitement des erreurs directement dans la fonction qui récupère les données. Si vous gérez une base de code partagée dans une grande entreprise, cela est particulièrement bénéfique, car vous pouvez forcer la consignation/la gestion correcte des erreurs sur les programmeurs les plus paresseux.

Exemple:

function displayData($row_id) {
    // Logging of the error would happen in this function
    $row = getRow($row_id);
    if($row === null) {
        // Handle the error here
    }

    // Do stuff here with data
}

function getRow($row_id) {
 $row = null;
 try{
     if(!$db->connected()) {
   throw excpetion("Couldn't Connect");
  }

  $result = $db->query($some_query_using_row_id);

  if(count($result) == 0 ) {
   throw new exception("Couldn't find a record!");
  }

  $row = $db->nextRow();

 } catch (db_exception) {
  //Log db conn error, alert admin, etc...
  return null; // This way I know that null means an error occurred
 }
 return $row;
}

C'est ma règle générale. Cela a bien fonctionné jusqu'à présent.

2
user197794

Pour mettre ce que d'autres ont dit d'une manière plus pithier ...

Les exceptions s'appliquent aux circonstances exceptionnelles

Si cette méthode est une couche d'accès aux données pure, je dirais que si un paramètre est inclus dans une instruction select, il est à craindre que je ne trouve aucune ligne à partir de laquelle construire un objet et que, par conséquent, renvoyer null serait acceptable, car est la logique d'accès aux données.

D'un autre côté, si je m'attendais à ce que mon paramètre reflète une clé primaire et que je ne récupère que n rangée, si j'en avais plus d'un, je lirais une exception. 0 est ok pour retourner null, 2 n'est pas.

Maintenant, si j'avais un code de connexion qui vérifiait auprès d'un fournisseur LDAP, puis dans une base de données pour obtenir plus de détails et que je m'attendais à ce qu'ils soient synchronisés à tout moment, je pourrais alors lancer l'exception. Comme d'autres l'ont dit, ce sont les règles commerciales.

Maintenant, je dirai que c'est une règle générale . Il y a des moments où vous voudrez peut-être rompre cela. Cependant, mon expérience et mes expériences avec C # (beaucoup de cela) et Java (un peu de cela) m’ont appris que c’est beaucoup plus coûteux en performances. traiter des exceptions que de traiter des problèmes prévisibles via une logique conditionnelle. Je parle de deux ou trois ordres de grandeur plus coûteux dans certains cas. Donc, s'il est possible que votre code se termine en boucle, je vous conseillerais de renvoyer null et de le tester.

2
Jim L

Si l'objet retourné est quelque chose qui peut être itéré, je renverrais un objet vide, de sorte que je n'ai pas à tester d'abord null.

Exemple:

bool IsAdministrator(User user)
{
    var groupsOfUser = GetGroupsOfUser(user);

    // This foreach would cause a run time exception if groupsOfUser is null.
    foreach (var groupOfUser in groupsOfUser) 
    {
        if (groupOfUser.Name == "Administrators")
        {
            return true;
        }
    }

    return false;
}
2
Jan Aagaard

J'aime ne pas renvoyer null à partir de n'importe quelle méthode, mais utiliser plutôt le type fonctionnel Option. Les méthodes qui ne peuvent renvoyer aucun résultat renvoient une option vide, plutôt que null.

De plus, les méthodes qui ne peuvent donner aucun résultat devraient l'indiquer par leur nom. Je mets normalement Try ou TryGet ou TryFind au début du nom de la méthode pour indiquer qu'elle peut renvoyer un résultat vide (par exemple, TryFindCustomer, TryLoadFile, etc.).

Cela permet à l'appelant d'appliquer différentes techniques, telles que le traitement en pipeline de la collecte (voir Martin Fowler's Collection Pipeline ) sur le résultat.

Voici un autre exemple où retourner Option au lieu de null est utilisé pour réduire la complexité du code: Comment réduire la complexité cyclomatique: Type de fonction de l'option

2
Zoran Horvat

Je pense que les fonctions ne devraient pas retourner null, pour la santé de votre base de code. Je peux penser à plusieurs raisons:

Il y aura une grande quantité de clauses de garde traitant la référence nulle if (f() != null).

Qu'est-ce que null, s'agit-il d'une réponse acceptée ou d'un problème? Est-ce que null est un état valide pour un objet spécifique? (imaginez que vous êtes un client pour le code). Je veux dire que tous les types de référence peuvent être nuls, mais devraient-ils?

Avoir null traîner donnera presque toujours quelques exceptions inattendues NullRef de temps en temps à mesure que votre base de code s'agrandit.

Il y a des solutions, tester-doer pattern ou en mettant en œuvre le option type de la programmation fonctionnelle.

1
gavri

Plus de viande à Grind: disons que mon DAL renvoie un NULL pour GetPersonByID comme conseillé par certains. Que doit faire ma BLL (plutôt mince) si elle reçoit une valeur NULL? Transmettez cette valeur NULL et laissez le consommateur final s’inquiéter (dans ce cas, une page ASP.Net)? Que diriez-vous d'avoir le BLL jeter une exception?

Le BLL peut être utilisé par ASP.Net et Win App, ou par une autre bibliothèque de classes. Je pense qu'il est injuste d'attendre du consommateur final qu'il sache intrinsèquement que la méthode GetPersonByID renvoie null (à moins que des types nuls ne soient utilisés, je suppose. ).

Ma prise (pour ce que cela vaut) est que mon DAL renvoie NULL si rien n'est trouvé. POUR CERTAINS OBJETS, ce n'est pas grave - cela pourrait être un 0: une liste de choses, donc ne rien avoir est correct (par exemple une liste de livres préférés). Dans ce cas, mon BLL renvoie une liste vide. Pour la plupart des choses concernant une seule entité (utilisateur, compte, facture, par exemple), si je n'en ai pas, c'est certainement un problème et une exception coûteuse. Toutefois, le fait de récupérer un utilisateur à l'aide d'un identificateur unique préalablement fourni par l'application devrait toujours renvoyer un utilisateur, l'exception étant une exception "appropriée", comme c'est exceptionnel. Le consommateur final de la BLL (ASP.Net, f'rinstance) s'attend à ce que les choses se déroulent bien, donc un gestionnaire d'exception non géré sera utilisé au lieu d'encapsuler chaque appel de GetPersonByID dans un bloc try-catch.

S'il y a un problème criant dans mon approche, faites-le moi savoir car je suis toujours désireux d'apprendre. Comme d’autres affiches l’ont dit, les exceptions sont coûteuses et l’approche consistant à "vérifier d’abord" est bonne, mais les exceptions devraient être tout simplement exceptionnelles.

Je profite de cet article et de nombreuses suggestions pour des scénarios "ça dépend" :-)

1
Mike Kingscott

Je suis d'accord avec la plupart des posts ici, qui tendent vers null.

Mon raisonnement est que générer un objet vide avec des propriétés non nullables peut causer des bugs. Par exemple, une entité avec un int ID propriété aurait une valeur initiale de ID = 0, qui est une valeur entièrement valide. Si cet objet, dans certaines circonstances, était sauvegardé dans une base de données, ce serait une mauvaise chose.

Pour tout ce qui a un itérateur, je utiliserais toujours la collection vide. Quelque chose comme

foreach (var eachValue in collection ?? new List<Type>(0))

est le code odeur à mon avis. Les propriétés de collection ne doivent jamais être nulles.

Un cas Edge est String. Beaucoup de gens disent, String.IsNullOrEmpty _ n'est pas vraiment nécessaire, mais vous ne pouvez pas toujours distinguer entre une chaîne vide et null. En outre, certains systèmes de base de données (Oracle) ne les distinguent pas du tout ('' est stocké sous la forme DBNULL), vous devez donc les gérer de manière égale. La raison en est que la plupart des valeurs de chaîne proviennent de la saisie de l'utilisateur ou de systèmes externes, alors que ni les zones de texte ni la plupart des formats d'échange n'ont de représentations différentes pour '' et null. Ainsi, même si l'utilisateur souhaite supprimer une valeur, il ne peut rien faire de plus que d'effacer le contrôle de saisie. De plus, la distinction entre les champs nullable et non nullable nvarchar de la base de données est plus que douteuse, si votre SGBD n’est pas Oracle - un champ obligatoire qui autorise '' est bizarre, votre interface utilisateur ne le permettrait jamais, vos contraintes ne sont donc pas mappées. Donc, la réponse ici, à mon avis, est de les traiter également, toujours.

En ce qui concerne votre question concernant les exceptions et les performances: si vous générez une exception que vous ne pouvez pas gérer complètement dans la logique de votre programme, vous devez abandonner, à un moment donné, quel que soit votre programme, et demander à l'utilisateur de répéter ce qu'il vient de faire. Dans ce cas, la pénalité de performance d'un catch est vraiment le moindre de vos soucis - il faut demander à l'utilisateur d'éléphant dans la pièce (ce qui implique de refaire le rendu de toute l'interface utilisateur, ou d'envoyer du HTML via le l'Internet). Donc, si vous ne suivez pas l'anti-pattern de " Flux de programme avec exceptions ", ne vous inquiétez pas, lancez-en un si cela a du sens. Même dans les cas limites, tels que "Exception de validation", les performances ne sont vraiment pas un problème, car vous devez demander à nouveau à l'utilisateur, dans tous les cas.

0
Oliver Schimmer

Je suis perplexe devant le nombre de réponses (sur le Web) indiquant que vous avez besoin de deux méthodes: une méthode "IsItThere ()" et une méthode "GetItForMe ()", ce qui conduit à une situation de concurrence critique. Quel est le problème avec une fonction qui renvoie null, l'assigne à une variable et vérifie que la variable a la valeur NULL tout en un test? Mon ancien code C était parsemé de

if (NULL! = (variable = fonction (arguments ...))) {

Donc, vous obtenez la valeur (ou null) dans une variable et le résultat en une fois. Cet idiome a-t-il été oublié? Pourquoi?

0
no comprende

Un modèle TryGet asynchrone:

Pour les méthodes synchrones, je crois que @ Johann Gerell'sréponse est le motif à utiliser dans tous les cas.

Toutefois, le modèle TryGet avec le paramètre out ne fonctionne pas avec les méthodes asynchrones.

Avec les littéraux nuptiaux de C # 7, vous pouvez maintenant le faire:

async Task<(bool success, SomeObject o)> TryGetSomeObjectByIdAsync(Int32 id)
{
    if (InternalIdExists(id))
    {
        o = await InternalGetSomeObjectAsync(id);

        return (true, o);
    }
    else
    {
        return (false, default(SomeObject));
    }
}
0
ttugates