2012-04-28 17 views
5

Buscando alguna guía de mejores prácticas. Digamos que tengo una línea de código como este:Cómo comprobar nulo en referencias anidadas

Color color = someOrder.Customer.LastOrder.Product.Color; 

donde al cliente, LastOrder, Producto y color puede ser null en condiciones normales. Me gustaría que el color sea nulo si alguno de los objetos en la ruta es nulo, sin embargo; para evitar excepciones de referencia nulas, necesitaría verificar la condición nula para cada uno de los objetos, p.

Color color = someOrder == null || 
       someOrder.Customer == null || 
       someOrder.Customer.LastOrder == null || 
       someOrder.Customer.Product == null ? 
       null : someOrder.Customer.LastOrder.Product.Color; 

o que podía hacer esto

Color color = null; 
try {color = someOrder.Customer.LastOrder.Product.Color} 
catch (NullReferenceException) {} 

El primer método funciona con claridad, pero parece un poco más tedioso de código y más difícil de leer. La segunda forma es un poco más fácil, pero probablemente no es una buena idea usar el manejo de excepciones para esto.

¿Hay alguna otra forma de atajo para verificar nulos y asignar null a color si es necesario? ¿O alguna idea sobre cómo evitar NullReferenceExceptions al usar tales referencias anidadas?

+2

posible duplicado de (http [profunda nulo comprobar, hay una manera mejor?]: // stackoverflow .com/questions/2080647/deep-null-checking-is-there-a-better-way) –

+0

@MarkByers sí, gracias por la referencia al otro pregunta er –

Respuesta

5

Está buscando el operador de desreferenciación seguro de nulos.

Color color = someOrder?.Customer?.LastOrder?.Product?.Color; 

Desafortunadamente C# no lo admite. Tal vez se agregará más tarde, pero no hay planes para hacerlo en este momento.

relacionada

+4

actualización de 2014, C# 6 lo admite ahora. –

+0

Ahora compatible con http://stackoverflow.com/a/2081709/1659248 –

0

Sin duda alguna lo prefiere el primer método ... el segundo explota el mecanismo de excepción para el flujo del programa que está mal en mi humilde opinión la práctica ...

AFAIK no hay un atajo o "operador de desreferenciación seguro de nulos" en C#.

0

Define un método único para acceder a las propiedades anidadas. Por ejemplo como esto

private Customoer GetCustomer(Order order) 
{ 
    return order != null ? order.Customer : null; 
} 

private Order GetLastOrder(Customer customer) 
{ 
    return customer != null ? customer.LastOrder : null; 
} 

Utilizando el método definido el acceso a sus propiedades a través de la aplicación

1

La mejor práctica es seguir Law of Demeter que suena como: no hablan con extraños. Es decir. objeto debe evitar invocar métodos de un objeto miembro devuelto por otro método. Esto permite escribir código menos acoplado, más fácil de mantener y legible.

Por lo tanto, evite utilizar 'restos de trenes' como someOrder.Customer.LastOrder.Product.Color, porque violan completamente la Ley de Demeter. Incluso es difícil entender qué negocio significa este código. ¿Por qué obtiene el color del producto de otro orden, que no es el actual?

Posible forma de eliminar el accidente del tren: empuje la funcionalidad más cerca del final interesante del accidente. En su caso, también considere pasar el último producto a su método, en lugar de usar un poco de orden.

+0

Gracias. Echaré un vistazo a LoD. Por cierto, el código era solo un ejemplo que inventé, sin significado comercial. –

+1

Me gusta que alguien haya dicho esto a pesar de que no responde DIRECTAMENTE la pregunta. No hay duda de que debes escribir código complejo para asegurarte de que no termines tratando de usar una referencia nula en un código como ese. Si bien es importante que conozca la respuesta técnica, incluido lo que C# es capaz de hacer y no es, este tipo de código debería asustarlo para que mire su diseño general. –

1

donde necesita lograr esto haga esto.

Uso

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color); 

o

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color); 

clase auxiliar Implementación

public static class Complex 
{ 
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func) 
    { 
     return Get(() => func(root)); 
    } 

    public static T Get<T>(Func<T> func) 
    { 
     try 
     { 
      return func(); 
     } 
     catch (Exception) 
     { 
      return default(T); 
     } 
    } 
} 
Cuestiones relacionadas