Vérifier si un objet est nul en C #

226

Je voudrais empêcher tout traitement supplémentaire sur un objet s'il est nul.

Dans le code suivant, je vérifie si l'objet est nul soit:

if (!data.Equals(null))

et

if (data != null)

Cependant, je reçois un NullReferenceExceptionat dataList.Add(data). Si l'objet était nul, il n'aurait même jamais dû entrer dans la ifdéclaration-!

Ainsi, je demande si c'est une bonne façon de vérifier si un objet est nul:

public List<Object> dataList;
public  bool AddData(ref Object data)
    bool success = false;
    try
    {
        // I've also used "if (data != null)" which hasn't worked either
        if (!data.Equals(null))
        {
           //NullReferenceException occurs here ...
           dataList.Add(data);
           success = doOtherStuff(data);
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.ToString());
    }
    return success;
}

Si c'est la bonne façon de vérifier si l'objet est nul, que fais-je de mal (comment puis-je empêcher un traitement supplémentaire sur l'objet pour éviter la NullReferenceException)?

développeur
la source
13
Vous devez également utiliser throw e;versusthrow new Exception(e.ToString());
Nix
17
en C #, vous devez toujours utiliser != nulldans vos vérifications nulles. .Equalsgénérera toujours une exception si l'objet est nul.
Kyle Trauberman
42
@Nix: throw e;n'est pas beaucoup mieux. throw;, d'autre part ...
Jon
4
@developer: e.ToString()produira une chaîne qui inclut non seulement le message d'erreur, mais aussi ceux de tous InnerExceptionset la trace de la pile. C'est donc une sorte de message d'exception très lourd. Si vous souhaitez (à juste titre!) Conserver ces informations et les conserver à leur place, utilisez-les simplement throw;.
Jon
14
Le try / catch ne fait rien pour le moment. Tout le monde dit d'utiliser simplement "throw" mais si vous ne faites rien à l'exception de le relancer, pourquoi avoir un bloc try / catch? Habituellement, vous interceptez des exceptions pour les gérer avec élégance, nettoyez les ressources (mieux avec la clause "finalement") ou effectuez une sorte de journalisation avant de relancer l'exception. Rien de tout cela ne se produit dans ce code, il n'est donc pas nécessaire d'essayer / attraper du tout.
David Peterson

Réponses:

252

Ce n'est pas dataça null, mais dataList.

Vous devez en créer un avec

public List<Object> dataList = new List<Object>();

Encore mieux: puisque c'est un champ, faites-le private. Et si rien ne vous empêche, faites-le aussi readonly. Juste une bonne pratique.

De côté

La bonne façon de vérifier la nullité est if(data != null). Ce type de vérification est omniprésent pour les types de référence; Nullable<T>remplace même l'opérateur d'égalité pour être un moyen plus pratique d'exprimer nullable.HasValuelors de la vérification de la nullité.

Si vous le faites, if(!data.Equals(null))vous obtiendrez un NullReferenceExceptionif data == null. Ce qui est assez comique, car éviter cette exception était l'objectif en premier lieu.

Vous faites également ceci:

catch (Exception e)
{
    throw new Exception(e.ToString());
}

Ce n'est certainement pas bon. Je peux imaginer que vous l'avez mis là juste pour pouvoir pénétrer dans le débogueur tout en restant dans la méthode, auquel cas ignorez ce paragraphe. Sinon, ne prenez pas d'exceptions pour rien. Et si vous le faites, retournez-les en utilisant simplement throw;.

Jon
la source
5
J'ai également vu Object.ReferenceEquals (obj, null) à cet effet. Est-ce pour éviter les dérogations à l'égalité?
Luca
2
@LucaPiccioni Je l'ai utilisé pour empêcher les plaintes de type valeur lors de l'utilisation de génériques: geekality.net/2009/11/13/generics-and-checking-for-null
Svish
4
Je préfère null != data. Mettre la constante en premier transforme la typographie bonehead null = dataen une erreur de compilation, plutôt qu'en une affectation involontaire. ( ==
Fonctionne
6
@ jpmc26: En C # if (data = null)est déjà une erreur de compilation, donc même s'il a fallu des décennies pour y arriver, nous n'avons plus vraiment besoin de faire attention à cela. Même les compilateurs C ++ produiront facilement un avertissement concernant une éventuelle affectation involontaire de ce code.
Jon
Luca, vous pouvez également éviter les remplacements d'égalité en transtypant en «objet» dans le test. Dans le même ordre d'idées, cette réponse devrait plutôt réclamer ceci: "if ((object) data! = Null)" car elle évite les erreurs lorsque l'égalité a été remplacée.
DAG
82

en C #> 7.0 utilisation

if (obj is null) ...

Cela ignorera tout == ou! = Défini par l'objet (sauf si vous voulez bien sûr les utiliser ...)

Pour une utilisation non nulle if (obj is object)(ou if (!(obj is null)))

kofifus
la source
1
Je me demande s'il y a un "n'est pas nul"? (python dirait obj is not null)
sehe
1
Pourquoi est-ce mieux que si (obj! = Null) qui est plus lisible
Orn Kristjansson
39
Je souhaite qu'ils mettent en œuvre if (obj aint null):(
Nick Bull
10
Car n'est pas nul il y aif (obj is object)
Yatskovsky
3
@OrnKristjansson car! = Et == peuvent être remplacés.
mitchellJ
61

C # 6 a une vérification nulle monadique :)

avant:

if (points != null) {
    var next = points.FirstOrDefault();
    if (next != null && next.X != null) return next.X;
}   
return -1;

après:

var bestValue = points?.FirstOrDefault()?.X ?? -1;
Jowen
la source
7
Parce que "les commentaires ne peuvent être modifiés que pendant 5 minutes"? Quoi? Quoi qu'il en soit ... Au fur et à mesure que j'y arrivais ... Je suis venu ici à la recherche d'une meilleure syntaxe pour exprimer result = myObject == null ? null : myObject.SomePropertyet votre exemple m'a poussé à écrire result = myObject?.SomeProperty. Homme!! C'est sournois. J'adore toujours le codage ...
Adam Cox
27

Votre dataList est nulle car elle n'a pas été instanciée, à en juger par le code que vous avez publié.

Essayer:

public List<Object> dataList = new List<Object>();
public  bool AddData(ref Object data)
bool success = false;
try
{
    if (!data.Equals(null))   // I've also used if(data != null) which hasn't worked either
    {
       dataList.Add(data);                      //NullReferenceException occurs here
       success = doOtherStuff(data);
    }
}
catch (Exception e)
{
    throw new Exception(e.ToString());
}
return success;

}

glosrob
la source
3
Aussi, juste pour ajouter, si les données sont nulles, elles ne planteront pas, vous pouvez ajouter null à un List <Object>.
DaveShaw
7
Mais essayer de faire .Equals sur un null déclencherait une exception. Devrait faire! = Null
glosrob
@glosrob: Ah !! Quel oubli! Je pensais que l'exception NullReferenceException provenait de l'objet .. pas de la liste! Je suis nouveau sur c # et je me suis dit qu'il y avait un moyen spécial de vérifier null en c #!
développeur
Cela aussi, mais j'ai vu qu'Ed S. l'avait couvert.
DaveShaw
1
@DaveShaw: Merci pour l'avertissement. Je veux éviter qu'un objet nul ne soit ajouté pour un traitement ultérieur, donc je vais quand même faire une vérification. :)
développeur
19

[Modifié pour refléter l'indice par @ kelton52]

La façon la plus simple est de faire object.ReferenceEquals(null, data)

Puisqu'il (null==data)n'est PAS garanti de fonctionner:

class Nully
{
    public static bool operator ==(Nully n, object o)
    {
        Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
        return true;
    }
    public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
    var data = new Nully();
    Console.WriteLine(null == data);
    Console.WriteLine(object.ReferenceEquals(null, data));
}

Produit:

Comparer '' avec 'Nully'

Vrai

Faux

gatopeich
la source
1
En fait, je viens d'essayer cela, et la remarque "L'avantage implicite est qu'il ignore tous les remplacements qui peuvent être présents dans la classe de données, comme" operator! = ". ' Ne semble pas vrai.
Kelly Elton
9

Non, vous devriez utiliser !=. Si dataest en fait null, votre programme se bloquera avec NullReferenceExceptionun résultat de la tentative d'appel de la Equalsméthode null. Sachez également que si vous souhaitez spécifiquement vérifier l'égalité de référence, vous devez utiliser la Object.ReferenceEqualsméthode car vous ne savez jamais comment Equalsa été implémentée.

Votre programme plante car il dataListest nul car vous ne l'initialisez jamais.

Ed S.
la source
7

Le problème dans ce cas n'est pas que datac'est nul. C'est çadataList lui même est nul.

À l'endroit où vous déclarez, dataListvous devez créer un nouvel Listobjet et l'affecter à la variable.

List<object> dataList = new List<object>();
Jeffrey L Whitledge
la source
5

En plus de la réponse @Jose Ortega , il est préférable d'utiliser une méthode d'extension

 public static bool IsNull(this object T)
     {
        return T == null;
     } 

Et utilisez la IsNullméthode pour tous les objets comme:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }
Ali
la source
1
Pourquoi return T == null ? true : false;et pas seulement return T == null;?
md2perpe
1
Je ne suis pas sûr d'être d'accord. Il semble étrange d'appeler une méthode sur un objet pour vérifier s'il est nul. Sans savoir que c'était une méthode d'extension, on pourrait penser qu'elle lèverait une exception de référence nulle.
Jamie Twells
Peut totalement confirmer que Jamie a raison - cela ne fonctionnera pas. Je sais parce que j'ai eu un moment de réflexion et j'ai écrit une méthode d'extension similaire: P Le code a toujours levé une exception de référence nulle, il n'entrera absolument pas dans la méthode d'extension.
James King
En fait, je veux dire que vous pouvez le faire avec la méthode d'extension ... le code peut avoir un problème et peut s'améliorer!
Ali
Vous pouvez appeler une méthode d'extension sur un objet nul; il suffit de comparer T (dans ce cas) avec null pour être prudent. Jamie a raison, cependant, cela semble étrange.
Tim Barrass
3

Depuis C # 8, vous pouvez utiliser le modèle de propriété 'vide' (avec correspondance de modèle ) pour vous assurer qu'un objet n'est pas nul:

if (obj is { })
{
    // 'obj' is not null here
}

Cette approche signifie " si l'objet fait référence à une instance de quelque chose " (c'est-à-dire qu'il n'est pas nul).

Vous pouvez penser à cela comme le contraire de: if (obj is null).... qui retournera vrai lorsque l'objet ne fait pas référence à une instance de quelque chose.

Pour plus d'informations sur les modèles en C # 8.0, lisez ici .

Darren Ruane
la source
3

À partir de C # 9, vous pouvez le faire

if (obj is null) { ... }

Pour une utilisation non nulle

if (obj is not object) { ... }

Si vous devez remplacer ce comportement, utilisez ==et en !=conséquence.

Eugene Chybisov
la source
2

Jeffrey L Whitledge a raison. Votre objet `dataList´ lui-même est nul.

Il y a aussi un autre problème avec votre code: vous utilisez le mot-clé ref, ce qui signifie que les données d'argument ne peuvent pas être nulles! Le MSDN dit:

Un argument passé à un paramètre ref doit d'abord être initialisé. Cela diffère de out, dont les arguments n'ont pas besoin d'être explicitement initialisés avant d'être passés

Ce n'est pas non plus une bonne idée d'utiliser des génériques avec le type `Object´. Les génériques doivent éviter la boxe / unboxing et également assurer la sécurité du type. Si vous voulez un type commun, rendez votre méthode générique. Enfin, votre code devrait ressembler à ceci:

public class Foo<T> where T : MyTypeOrInterface {

      public List<T> dataList = new List<T>();

      public bool AddData(ref T data) {
        bool success = false;
        try {
          dataList.Add(data);                   
          success = doOtherStuff(data);
        } catch (Exception e) {
          throw new Exception(e.ToString());
        }
        return success;
      }

      private bool doOtherStuff(T data) {
        //...
      }
    }
DiableNoir
la source
2

Comme d’autres l’ont déjà souligné, il n’est pas, datamais plutôt probable dataList,null . En plus de ça...

catch- throwest un antipattern qui me donne presque toujours envie de vomir à chaque fois que je le vois. Imaginez que quelque chose tourne mal au fond de quelque chose qui doOtherStuff()appelle. Tout ce que vous récupérez est un Exceptionobjet, jeté à l' throwintérieur AddData(). Aucune trace de pile, aucune information d'appel, aucun état, rien du tout pour indiquer la véritable source du problème, sauf si vous entrez et basculez votre débogueur pour interrompre l'exception levée plutôt que l'exception non gérée. Si vous attrapez une exception et que vous la relancez de quelque manière que ce soit , en particulier si le code dans le bloc try n'est pas trivial, faites-vous (et vos collègues, présents et futurs) une faveur et jetez l'ensembletry - catchbloc . Accordé,throw;est meilleur que les alternatives, mais vous vous donnez toujours (ou à quiconque essaie de corriger un bogue dans le code) des maux de tête complètement inutiles. Cela ne veut pas dire que try-catch-throw est nécessairement mauvais en soi, tant que vous faites quelque chose de pertinent avec l'objet d'exception qui a été jeté à l'intérieur du bloc catch.

Ensuite, il y a les problèmes potentiels de capture Exceptionen premier lieu, mais c'est une autre question, d'autant plus que dans ce cas particulier, vous jetez une exception.

Une autre chose qui me semble plus que peu dangereuse est qu'elle datapourrait potentiellement changer de valeur pendant l'exécution de la fonction, puisque vous passez par référence. Ainsi, la vérification nulle peut réussir, mais avant que le code ne fasse quoi que ce soit avec la valeur, il est changé - peut-être en null. Je ne suis pas sûr que ce soit une préoccupation ou non (ce n'est peut-être pas le cas), mais cela semble valoir la peine d'être surveillé.

un CVn
la source
2
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

utilisation:

isnull(object.check.it)

Utilisation conditionnelle:

isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;

Mise à jour (d'une autre manière) mise à jour le 31/08/2017. Merci pour le commentaire.

public static bool isnull(object T)
{
    return T ? true : false;
}
Jose Ortega
la source
5
cond ? true : false;est complètement équivalent à juste cond. Cela n'ajoute rien.
lericson
Je suis désolé mais si vous cochez la fonction, elle doit retourner une valeur booléenne. Je fais le formalisme. Alors revérifiez
Jose Ortega
3
il signifie return T == null;aussi renvoie un booléen!
MQoder
Je sais ce qu'il dit. ty
Jose Ortega
1
Au lieu de return T == null ? true : false;simplement utiliser return T == null;.
md2perpe
1

Chaque fois que vous créez des objets de classe, vous devez vérifier si l'objet est nul ou non en utilisant le code ci-dessous.

Exemple: object1 est un objet de classe

void myFunction(object1)
{
  if(object1!=null)
  {
     object1.value1 //If we miss the null check then here we get the Null Reference exception
  }
}
user3483639
la source
0

Je viens de suivre une méthode que nous suivions habituellement en script java. Pour convertir un objet en chaîne, puis vérifiez s’ils sont nuls.

var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
  // code as per your needs
}
Mohan Stanky
la source
0

J'ai fait plus simple (façon positive) et ça semble bien fonctionner.

Étant donné que tout type d '"objet" est au moins un objet


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
Gilles5678
la source