web-dev-qa-db-fra.com

Vérifier la nullité dans la boucle foreach

Existe-t-il un moyen plus agréable de procéder comme suit:
J'ai besoin d'une vérification pour que null apparaisse sur file.Headers avant de poursuivre la boucle 

if (file.Headers != null)
{
  foreach (var h in file.Headers)
  {
   //set lots of properties & some other stuff
  }
}

En bref, il semble un peu moche d’écrire le foreach à l’intérieur du if en raison du niveau d’indentation dans mon code.

Est-ce quelque chose qui évaluerait à 

foreach(var h in (file.Headers != null))
{
  //do stuff
}

possible?

60
Eminem

Juste comme un ajout cosmétique à la suggestion de Rune, vous pouvez créer votre propre méthode d’extension:

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

Ensuite, vous pouvez écrire:

foreach (var header in file.Headers.OrEmptyIfNull())
{
}

Changer le nom selon les goûts :)

87
Jon Skeet

En supposant que le type d’éléments dans file.Headers soit T, vous pouvez le faire.

foreach(var header in file.Headers ?? Enumerable.Empty<T>()){
  //do stuff
}

cela créera un énumérable vide de T si file.Headers est null. Si le type de fichier est un type que vous possédez, je souhaiterais toutefois modifier le getter de Headers à la place. null est la valeur de unknown, donc si possible, au lieu d'utiliser null comme "je sais qu'il n'y a pas d'éléments", alors que null doit (en fait) être interprété comme "je ne sais pas s'il y a des éléments", utilisez un ensemble vide pour montrer vous savez qu'il n'y a pas d'éléments dans l'ensemble. Ce serait aussi DRY'er puisque vous n'aurez pas à faire le contrôle nul aussi souvent.

EDITpour donner suite à la suggestion de Jons, vous pouvez également créer une méthode d’extension transformant le code ci-dessus en 

foreach(var header in file.Headers.OrEmptyIfNull()){
  //do stuff
}

Dans le cas où vous ne pouvez pas changer le getter, ce serait ma préférence, car il exprime plus clairement l'intention en donnant à l'opération un nom (OrEmptyIfNull).

54
Rune FS

Franchement, je conseille: il suffit de sucer le test null. Un test null est just une brfalse ou brfalse.s; tout le reste impliquera beaucoup plus de travail (tests, assignations, appels de méthodes supplémentaires, GetEnumerator(), MoveNext(), Dispose() inutiles, sur l'itérateur, etc.).

Un test if est simple, évident et efficace.

13
Marc Gravell

le "si" avant l'itération est correct, peu de ces "jolies" sémantiques peuvent rendre votre code moins lisible.

de toute façon, si l'indentation vous perturbe, vous pouvez modifier le si pour vérifier:

if(file.Headers == null)  
   return;

et vous ne pourrez accéder à la boucle foreach que lorsqu'il existe une valeur vraie à la propriété d'en-têtes.

une autre option à laquelle je peux penser est d'utiliser l'opérateur null-coalescing à l'intérieur de votre boucle foreach et d'éviter complètement la vérification de null ..

List<int> collection = new List<int>();
collection = null;
foreach (var i in collection ?? Enumerable.Empty<int>())
{
    //your code here
}

(remplacez la collection par votre vrai objet/type)

10
Tamir

J'utilise une petite méthode d'extension Nice pour ces scénarios:

  public static class Extensions
  {
    public static IList<T> EnsureNotNull<T>(this IList<T> list)
    {
      return list ?? new List<T>();
    }
  }

Étant donné que Headers est de type list, vous pouvez faire ce qui suit:

foreach(var h in (file.Headers.EnsureNotNull()))
{
  //do stuff
}
3
Wolfgang Ziegler

Utilisation de Opérateur Null-conditionnel et ForEach () qui fonctionne plus rapidement que la boucle standard foreach.
Vous devez cependant convertir la collection en liste.

   listOfItems?.ForEach(item => // ... );
1
Andrei Karcheuski

Dans certains cas, je préférerais légèrement une autre variante générique, en partant du principe que les constructeurs de collection par défaut renvoient des instances vides.

Il serait préférable de nommer cette méthode NewIfDefault. Cela peut être utile non seulement pour les collections, donc la contrainte de type IEnumerable<T> est peut-être redondante.

public static TCollection EmptyIfDefault<TCollection, T>(this TCollection collection)
        where TCollection: class, IEnumerable<T>, new()
    {
        return collection ?? new TCollection();
    }
0
N. Kudryavtsev