223 votes

Pourquoi la boucle foreach de .NET lève-t-elle une exception NullRefException lorsque la collection est nulle ?

Je me retrouve donc fréquemment dans cette situation... où Do.Something(...) renvoie une collection nulle, comme ceci :

int[] returnArray = Do.Something(...);

Ensuite, j'essaie d'utiliser cette collection comme suit :

foreach (int i in returnArray)
{
    // do some more stuff
}

Je suis juste curieux, pourquoi une boucle foreach ne peut-elle pas fonctionner sur une collection nulle ? Il me semble logique qu'aucune itération ne soit exécutée avec une collection nulle... au lieu de cela, la boucle lève un NullReferenceException . Quelqu'un sait-il pourquoi cela pourrait être le cas ?

C'est ennuyeux car je travaille avec des API qui ne sont pas claires sur ce qu'elles retournent exactement, donc je me retrouve avec if (someCollection != null) partout...

Edit : Merci à tous d'avoir expliqué cela foreach utilise GetEnumerator et s'il n'y a pas d'énumérateur à récupérer, le foreach échouerait. Je suppose que je me demande pourquoi le langage/exécution ne peut pas ou ne veut pas faire une vérification de nullité avant de récupérer l'énumérateur. Il me semble que le comportement serait toujours bien défini.

242voto

Robaticus Points 14665

Eh bien, la réponse courte est "parce que c'est la façon dont les concepteurs du compilateur l'ont conçu". En réalité, cependant, votre objet de collection est nul, donc il n'y a aucun moyen pour le compilateur d'obtenir que l'énumérateur boucle à travers la collection.

Si vous avez vraiment besoin de faire quelque chose comme ça, essayez l'opérateur de coalescence null :

int[] array = null;

foreach (int i in array ?? Enumerable.Empty<int>())
{
   System.Console.WriteLine(string.Format("{0}", i));
}

146voto

SLaks Points 391154

A foreach appelle la boucle GetEnumerator méthode.
Si la collection est null cet appel de méthode donne lieu à un NullReferenceException .

C'est une mauvaise pratique de renvoyer un null vos méthodes doivent retourner une collection vide à la place.

47voto

Reed Copsey Points 315315

Il y a une grande différence entre une collection vide et une référence nulle à une collection.

Lorsque vous utilisez foreach En interne, il s'agit d'appeler la méthode de calcul de l'IEnumerable GetEnumerator () méthode. Si la référence est nulle, cette exception est levée.

Cependant, il est tout à fait valable d'avoir un site vide IEnumerable o IEnumerable<T> . Dans ce cas, foreach ne "itérera" pas sur quoi que ce soit (puisque la collection est vide), mais il ne lancera pas non plus de requête, puisque c'est un scénario parfaitement valide.


Edit :

Personnellement, si vous devez contourner ce problème, je recommanderais une méthode d'extension :

public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original)
{
     return original ?? Enumerable.Empty<T>();
}

Vous pouvez alors simplement appeler :

foreach (int i in returnArray.AsNotNull())
{
    // do some more stuff
}

5voto

JAB Points 11053

Parce qu'une collection nulle n'est pas la même chose qu'une collection vide. Une collection vide est un objet de collection sans éléments ; une collection nulle est un objet inexistant.

Voici quelque chose à essayer : Déclarez deux collections de n'importe quelle sorte. Initialisez l'une d'elles normalement pour qu'elle soit vide, et attribuez à l'autre la valeur null . Essayez ensuite d'ajouter un objet aux deux collections et voyez ce qui se passe.

3voto

Henk Holterman Points 153608

C'est la faute de Do.Something() . La meilleure pratique ici serait de retourner un tableau de taille 0 (c'est possible) au lieu d'un null.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X