Pregunta sobre syntax, .net, c#, web – Manera elegante de evitar NullReferenceException en C #

7

quiero hacer esto

var path = HttpContext.Current.Request.ApplicationPath;

Si alguna de las propiedades en el camino es nula, quiero que la ruta sea nula o "" sería mejor.

¿Hay una manera elegante de hacer esto sin los ternarios?

idealmente me gustaría este comportamiento (sin el horrible rendimiento y la fealdad) ruta de cadena;

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

Gracias

He leído mal y borrado el comentario Carl Winder

Tu respuesta

4   la respuesta
11
[EDITAR]

n nula?., lo que simplificaría su caso a:

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

Por razones históricas, la respuesta para versiones de idiomas anteriores se puede encontrar a continuación.

Supongo que estás buscando el operador seguro de desreferenciación de Groovy?., y tú eresno el primero Desde el tema vinculado, la solución que más me gusta personalmente eséste (ese se ve bastante bien también). Entonces puedes simplemente hacer:

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

Siempre puedes acortar un poco el nombre de la función. Esto devolverá nulo si alguno de los objetos en la expresión es nulo, ApplicationPath de lo contrario. Para los tipos de valor, tendría que realizar una comprobación nula al final. De todos modos, no hay otra manera hasta ahora, a menos que quiera verificar nulo en todos los niveles.

Aquí está el método de extensión utilizado anteriormente:

    public static class Extensions
    {
    // safe null-check.
    public static TOut IfNotNull<TIn, TOut>(this TIn v, Func<TIn, TOut> f) 
            where TIn : class  
            where TOut: class 
            { 
                    if (v == null) return null; 
                    return f(v); 
            }       
    }
@AK_ No, no puede simplemente definir el operador de su propia marca y anularlo ... Eso sería desagradable en este caso :) El equipo .NET es consciente de las "solicitudes" hechas para este tipo de funcionalidad, pero AFAIK ganó. no se envía en C # 5 ->aquí yaquí Patryk Ćwiek
¡Quiéralo! También se agregó el método de extensión a nuestra biblioteca de marcos. Timo Kosig
Agregó el método de extensión que ha usado en su ejemplo. Buena solución! Matt
(Continúa, bah, tiempo de espera en las ediciones) No puedo ver una manera de anular esta funcionalidad como operador, considerando que acepta una expresión lambda. No sé si eso es posible, pero incluso si lo fuera, sería feo. :). Además, la sobrecarga de un operador existente para un tipo arbitrario (si fuera posible) revelaría un campo completamente nuevo para colisiones y WTF inesperados. Patryk Ćwiek
¿Alguna forma sensata de anular un operador para hacer esto? AK_
2

cuando hizo la pregunta, no vi una solución más sencilla que el intento ... la captura que ha proporcionado. La única alternativa: comprobar cada parte contra nula con "if" o "?" Parecía más feo (pero posiblemente sea un poco más rápido).

O bien tenías que escribir:

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

o:

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

Ambos lo están haciendo sin excepción. Tenga en cuenta que ambos utilizan "accesos directos" para abortar la comprobación si se encuentra algún valor nulo.

Actualización (diciembre de 2017): Ya queC # versión 6 y superior, Hay una mejor solución disponible, la llamadaElvis-Operador (también conocido como operador de fusión nula?. yx?[i] para matrices), que puede utilizar. El ejemplo de arriba

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

se ve mucho mejor de esta manera:

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

que hace exactamente lo mismo y, en mi opinión, es mucho más que "simplemente" azúcar sintáctica. Combinado con un anexo.?? value usted puede reemplazar fácilmentenull por algún otro valor, por ejemplo

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

Esto hace que elpath variable vacía si no se puede obtener un valor no nulo.

4

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

La forma más sencilla de implementar esto.NullHelpers.GetValueOrNull Probablemente sea algo como esto:

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

Pero, con mucho, la mejor manera de resolver esto es mediante el uso de árboles de Expresión:

public static T GetValueOrNull<T>(
    Expression<Func<T>> valueProvider) 
    where T : class
{
    var expression = (MemberExpression)
        ((MemberExpression)valueProvider.Body).Expression;

    var members = new List<MemberExpression>();

    while (expression != null)
    {
        members.Add(expression);

        expression = 
            (MemberExpression)expression.Expression;
    }

    members.Reverse();

    foreach (var member in members)
    {
        var func = Expression.Lambda<Func<object>>(member).Compile();

        if (func() == null)
        {
            return null;
        }
    }

    return valueProvider.Compile()();
}

Esta es también la forma más lenta de hacer las cosas, ya que cada llamada hará una o varias invocaciones de compilador JIT, pero ...

Todavía está bien ;-)

ACTUALIZACIÓN (Noviembre 2014)

C # 6 viene y contendrá algo que ellos llaman elOperador de propagacion nula, lo que significa que hay soporte de idioma para esto. Su ejemplo se puede escribir de la siguiente manera en C # 6:

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

Si alguna de las partes contiene un valor nulo, la expresión completa devolverá un valor nulo.

No creo que el segundo ejemplo funcione ... ¿no deberías empezar desde la parte inferior de la expresión? AK_
@AK_: Eso es lo quemembers.Reverse(); es para :-). Pruébalo tú mismo. Steven
2

nula en todos los niveles. Para reutilizarlo, puede envolver ese código en una función auxiliar o tal vez en un método de extensión. Esto le permitirá acceder de forma segura a través de esa función, pero aún así realizar la comprobación nula de manera consistente.

Ejemplo:

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 string RequestPath(this HttpContext context)
  {
    if (context == null || context.Request == null)
    {
      return default(string);
    }

    return context.Request.ApplicationPath;
  }
}
Es breve porque encapsula los controles en un método reutilizable; lo que significa que en cualquier momento que desee obtener el valor es solo una llamada a un solo método. Es mejor que tratar de realizar constantemente los mismos controles nulos en muchos lugares, y también más simple. STW
como es esto corto Hice algo muy similar con los ternarios ... AK_

Preguntas relacionadas