Manière élégante d’éviter NullReferenceException en C #

Je veux faire ça

var path = HttpContext.Current.Request.ApplicationPath; 

Si l’une des propriétés le long du chemin est nulle, je veux que le chemin soit nul, ou “” serait mieux.

Existe-t-il un moyen élégant de le faire sans ternaires?

idéalement, je voudrais ce comportement (sans la performance horrible et la laideur) chemin de la chaîne;

 try { path = HttpContext.Current.Request.ApplicationPath; } catch { path = null; } 

Je vous remercie

[MODIFIER]

C # 6 a été publié il y a quelque temps et a été livré avec un opérateur à propagation nulle ?. , ce qui simplifierait votre cas pour:

 var path = HttpContext?.Current?.Request?.ApplicationPath 

Pour des raisons historiques, les réponses pour les versions linguistiques précédentes sont disponibles ci-dessous.


Je suppose que vous recherchez l’opérateur de déréférencement sûr de Groovy ?. et vous n’êtes pas le premier. Parmi les sujets liés, la solution que j’aime personnellement le mieux est celle-ci ( celle-ci est très jolie aussi). Ensuite, vous pouvez simplement faire:

 var path = HttpContext.IfNotNull(x => x.Current).IfNotNull(x => x.Request).IfNotNull(x => x.ApplicationPath); 

Vous pouvez toujours raccourcir un peu le nom de la fonction. Cela renverra null si l’un des objects de l’expression est null, sinon ApplicationPath. Pour les types de valeur, vous devez effectuer une vérification nulle à la fin. Quoi qu’il en soit, il n’y a pas d’autre moyen jusqu’à présent, à moins que vous ne souhaitiez vérifier la valeur null à tous les niveaux.

Voici la méthode d’extension utilisée ci-dessus:

  public static class Extensions { // safe null-check. public static TOut IfNotNull(this TIn v, Func f) where TIn : class where TOut: class { if (v == null) return null; return f(v); } } 

Vous pouvez écrire quelque chose comme ceci:

 ssortingng value = NullHelpers.GetValueOrNull( () => HttpContext.Current.Request.ApplicationPath); 

Le moyen le plus simple d’implémenter ce NullHelpers.GetValueOrNull est probablement quelque chose comme ceci:

 public static T GetValueOrNull(Func valueProvider) where T : class { try { return valueProvider(); } catch (NullReferenceException) { return null; } } 

Mais de loin le meilleur moyen de résoudre ce problème consiste à utiliser des arbres d’expression:

 public static T GetValueOrNull( Expression> valueProvider) where T : class { var expression = (MemberExpression) ((MemberExpression)valueProvider.Body).Expression; var members = new List(); while (expression != null) { members.Add(expression); expression = (MemberExpression)expression.Expression; } members.Reverse(); foreach (var member in members) { var func = Expression.Lambda>(member).Comstack(); if (func() == null) { return null; } } return valueProvider.Comstack()(); } 

C’est aussi le moyen le plus lent de faire les choses, puisque chaque appel fera un ou plusieurs appels du compilateur JIT, mais …

C’est encore cool 😉

MISE À JOUR (novembre 2014)

C # 6 arrive et contient quelque chose qu’ils appellent l’ opérateur de propagation nulle , ce qui signifie qu’il existe un support linguistique pour cela. Votre exemple peut être écrit comme suit en C # 6:

 var path = HttpContext?.Current?.Request?.ApplicationPath; 

Si l’une des parties contient null, l’expression complète renvoie null.

Le chemin le plus court et le plus performant consiste à effectuer la vérification de nullité à chaque niveau. Pour la réutilisation, vous pouvez intégrer ce code dans une fonction d’assistance ou peut-être une méthode d’extension. Cela vous permettra d’y accéder en toute sécurité via cette fonction, tout en effectuant toujours la vérification de nullité.

Exemple:

 public void DoSomething() { // Get the path, which may be null, using the extension method var contextPath = HttpContext.Current.RequestPath; } public static class HttpContextExtensions { public static ssortingng RequestPath(this HttpContext context) { if (context == null || context.Request == null) { return default(ssortingng); } return context.Request.ApplicationPath; } } 

En mai 2012, lorsque vous avez posé la question, je n’ai pas vu de solution plus simple que la tentative … prise que vous avez fournie. La seule alternative – vérifier chaque partie contre null avec “si” ou “?” avait l’air plus laid (mais est peut-être un peu plus rapide).

Soit vous deviez écrire:

 path = HttpContext!=null ? (HttpContext.Current!=null ? (HttpContext.Current.Request!=null ?(HttpContext.Current.Request.ApplicationPath!=null ? HttpContext.Current.Request.ApplicationPath : null) : null) : null) : null; 

ou:

 if (HttpContext == null || HttpContext.Current == null || HttpContext.Current.Request == null || HttpContext.Current.Request.ApplicationPath == null) path = null; else path = HttpContext.Current.Request.ApplicationPath; 

les deux le font sans traitement d’exception. Notez que les deux utilisent des “raccourcis” pour abandonner la vérification si une valeur nulle est trouvée.


Mise à jour (décembre 2017): depuis la version 6 et les versions ultérieures de C #, il existe une meilleure solution, appelée Elvis -Operator (également connu sous le nom d’opérateur null-coalescing ?. Et x?[i] pour les tableaux), que vous pouvez utiliser. . L’exemple ci-dessus

 path = HttpContext!=null ? (HttpContext.Current!=null ? (HttpContext.Current.Request!=null ?(HttpContext.Current.Request.ApplicationPath!=null ? HttpContext.Current.Request.ApplicationPath : null) : null) : null) : null; 

semble beaucoup plus agréable de cette façon:

 path = HttpContext?.Current?.Request?.ApplicationPath; 

qui fait exactement la même chose et est à mon humble avis beaucoup plus que “juste” le sucre syntaxique. Combiné avec un ajouté ?? value ?? value vous pouvez facilement remplacer null par une autre valeur, par exemple

 path = (HttpContext?.Current?.Request?.ApplicationPath) ?? ""; 

Cela rend la variable de path vide si aucune valeur non NULL ne peut être obtenue.

En C # 8.0

Vous pouvez aussi utiliser le symbole d’exclamation “!” Pour éviter les valeurs nulles

 MyClass a; // Nullable reference type MyClass! b; // Non-nullable reference type a = null; // OK, this is nullable b = null; // Error, b is non-nullable b = a; // Error, n might be null, s can't be null WriteLine(b.ToSsortingng()); // OK, can't be null WriteLine(a.ToSsortingng()); // Warning! Could be null! if (a != null) { WriteLine(a.ToSsortingng); } // OK, you checked