Nota: Esta pregunta se hizo antes de la introducción del .?
operador en C # 6 / Visual Studio 2015 .
Todos hemos estado allí, tenemos algunas propiedades profundas como cake.frosting.berries.loader que debemos verificar si es nula para que no haya ninguna excepción. La forma de hacerlo es usar una declaración if de cortocircuito
if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...
Esto no es exactamente elegante, y quizás debería haber una forma más fácil de verificar toda la cadena y ver si se encuentra con una variable / propiedad nula.
¿Es posible usar algún método de extensión o sería una característica del lenguaje, o es solo una mala idea?
Respuestas:
Hemos considerado agregar una nueva operación "?" al lenguaje que tiene la semántica que deseas. (Y se ha agregado ahora; ver más abajo). Es decir, dirías
y el compilador generaría todas las comprobaciones de cortocircuito por usted.
No hizo la barra para C # 4. Tal vez para una futura versión hipotética del lenguaje.
Actualización (2014): El
?.
operador ahora está planeado para la próxima versión del compilador de Roslyn. Tenga en cuenta que todavía hay cierto debate sobre el análisis sintáctico y semántico exacto del operador.Actualización (julio de 2015): Visual Studio 2015 se lanzó y se entrega con un compilador de C # que admite los operadores
?.
y condicional nulo?[]
.fuente
Esta pregunta me inspiró para tratar de descubrir cómo se puede realizar este tipo de comprobación nula profunda con una sintaxis más fácil / bonita utilizando árboles de expresión. Si bien estoy de acuerdo con las respuestas que indican que podría ser un mal diseño si a menudo necesita acceder a instancias en lo profundo de la jerarquía, también creo que en algunos casos, como la presentación de datos, puede ser muy útil.
Así que creé un método de extensión, que te permitirá escribir:
Esto devolverá las Bayas si ninguna parte de la expresión es nula. Si se encuentra nulo, se devuelve nulo. Sin embargo, hay algunas advertencias, en la versión actual solo funcionará con acceso simple de miembros, y solo funciona en .NET Framework 4, porque usa el método MemberExpression.Update, que es nuevo en v4. Este es el código para el método de extensión IfNotNull:
Funciona examinando el árbol de expresión que representa su expresión y evaluando las partes una tras otra; cada vez comprobando que el resultado no es nulo.
Estoy seguro de que esto podría extenderse para que otras expresiones que no sean MemberExpression sean compatibles. Considere esto como un código de prueba de concepto, y tenga en cuenta que habrá una penalización de rendimiento al usarlo (lo que probablemente no importará en muchos casos, pero no lo use en un ciclo cerrado :-))
fuente
DynamicInvoke
allí. Religiosamente evito eso :)He encontrado que esta extensión es bastante útil para escenarios de anidación profunda.
Es una idea que obtuve del operador de fusión nula en C # y T-SQL. Lo bueno es que el tipo de retorno es siempre el tipo de retorno de la propiedad interna.
De esa manera puedes hacer esto:
... o una ligera variación de lo anterior:
No es la mejor sintaxis que conozco, pero funciona.
fuente
Además de violar la Ley de Deméter, como ya ha señalado Mehrdad Afshari, me parece que necesita una "verificación nula profunda" para la lógica de decisión.
Este suele ser el caso cuando desea reemplazar objetos vacíos con valores predeterminados. En este caso, debería considerar implementar el Patrón de objetos nulos . Actúa como un sustituto de un objeto real, proporcionando valores predeterminados y métodos de "no acción".
fuente
Actualización: a partir de Visual Studio 2015, el compilador de C # (versión de lenguaje 6) ahora reconoce al
?.
operador, lo que hace que la "comprobación nula profunda" sea muy sencilla. Ver esta respuesta para más detalles.Además de rediseñar su código, como sugiere esta respuesta eliminada , otra opción (aunque terrible) sería usar un
try…catch
bloque para ver siNullReferenceException
ocurre en algún momento durante esa búsqueda profunda de propiedades.Yo personalmente no haría esto por las siguientes razones:
NullReferenceException
s probablemente nunca debería ser atrapado explícitamente. (Ver esta pregunta )Es casi seguro que tendría que ser una función de lenguaje (que está disponible en C # 6 en forma de
.?
y?[]
operadores), a menos que C # ya tenía más sofisticado evaluación perezosa, o menos que desee utilizar la reflexión (que probablemente no es también una buena idea por razones de rendimiento y seguridad de tipo).Como no hay forma de pasar simplemente
cake.frosting.berries.loader
a una función (se evaluaría y arrojaría una excepción de referencia nula), tendría que implementar un método de búsqueda general de la siguiente manera: toma objetos y los nombres de propiedades para buscar:(Nota: código editado).
Rápidamente ve varios problemas con este enfoque. Primero, no obtienes ningún tipo de seguridad y posible boxeo de valores de propiedad de un tipo simple. En segundo lugar, puede regresar
null
si algo sale mal, y tendrá que verificar esto en su función de llamada, o lanzará una excepción y volverá a donde comenzó. Tercero, puede ser lento. Cuarto, parece más feo de lo que comenzaste.O me quedaría con:
o vaya con la respuesta anterior de Mehrdad Afshari.
PD: Cuando escribí esta respuesta, obviamente no consideraba los árboles de expresión para las funciones lambda; vea, por ejemplo, la respuesta de @driis para una solución en esta dirección. También se basa en un tipo de reflexión y, por lo tanto, podría no funcionar tan bien como una solución más simple (
if (… != null & … != null) …
), pero puede considerarse mejor desde el punto de vista de la sintaxis.fuente
Si bien la respuesta de driis es interesante, creo que es un rendimiento demasiado costoso. En lugar de compilar muchos delegados, preferiría compilar una lambda por ruta de propiedad, almacenarla en caché y luego volver a invocarla en muchos tipos.
NullCoalesce a continuación hace exactamente eso, devuelve una nueva expresión lambda con comprobaciones nulas y un retorno de default (TResult) en caso de que alguna ruta sea nula.
Ejemplo:
Devolverá una expresión
Código:
fuente
Una opción es usar el Patten de objetos nulos, así que en lugar de tener null cuando no tienes un pastel, tienes un NullCake que devuelve un NullFosting, etc. Lo siento, no soy muy bueno para explicar esto, pero otras personas lo son, mira
fuente
¡Yo también he deseado a menudo una sintaxis más simple! Se vuelve especialmente feo cuando tienes valores de retorno de método que pueden ser nulos, porque entonces necesitas variables adicionales (por ejemplo:
cake.frosting.flavors.FirstOrDefault().loader
)Sin embargo, aquí hay una alternativa bastante decente que utilizo: crear un método auxiliar Null-Safe-Chain. Me doy cuenta de que esto es bastante similar a la respuesta de @ John anterior (con el
Coal
método de extensión), pero creo que es más sencillo y menos tipeado. Así es como se ve:Aquí está la implementación:
También creé varias sobrecargas (con 2 a 6 parámetros), así como sobrecargas que permiten que la cadena termine con un tipo de valor o predeterminado. ¡Esto funciona muy bien para mí!
fuente
Hay un proyecto tal vez codeplex que implementa Quizás o IfNotNull usando lambdas para expresiones profundas en C #
Ejemplo de uso:
El enlace se sugirió en una pregunta similar ¿ Cómo verificar nulos en una expresión lambda profunda?
fuente
Como se sugiere en la respuesta de John Leidegren , un enfoque para evitar esto es utilizar métodos de extensión y delegados. Usarlos podría verse más o menos así:
La implementación es desordenada porque necesita que funcione para los tipos de valor, los tipos de referencia y los tipos de valores anulables. Puede encontrar una implementación completa en la respuesta de Timwi a ¿Cuál es la forma correcta de verificar los valores nulos? .
fuente
O puedes usar la reflexión :)
Función de reflexión:
Uso:
Mi caso (devuelve DBNull.Value en lugar de nulo en la función de reflexión):
fuente
Prueba este código:
fuente
Publiqué esto anoche y luego un amigo me señaló esta pregunta. Espero eso ayude. Entonces puedes hacer algo como esto:
Lea la publicación completa del blog aquí .
El mismo amigo también sugirió que veas esto .
fuente
Expression
si solo vas a compilar y atrapar? Solo usa aFunc<T>
.Modifiqué ligeramente el código desde aquí para que funcione para la pregunta que se hace:
Y sí, probablemente esta no sea la solución óptima debido a las implicaciones de rendimiento de prueba / captura, pero funciona:>
Uso:
fuente
Donde necesites lograr esto, haz esto:
Uso
o
Implementación de clase auxiliar
fuente
Me gusta el enfoque adoptado por Objective-C:
"El lenguaje Objective-C adopta otro enfoque para este problema y no invoca métodos en nulo, sino que devuelve nulo para todas esas invocaciones".
fuente