El operador de fusión nula en C # le permite acortar el código
if (_mywidget == null)
return new Widget();
else
return _mywidget;
Abajo a:
return _mywidget ?? new Widget();
Sigo encontrando que un operador útil que me gustaría tener en C # sería uno que le permitiera devolver una propiedad de un objeto, o algún otro valor si el objeto es nulo. Entonces me gustaría reemplazar
if (_mywidget == null)
return 5;
else
return _mywidget.Length;
Con:
return _mywidget.Length ??! 5;
No puedo evitar pensar que debe haber alguna razón para que este operador no exista. ¿Es un olor a código? ¿Hay alguna forma mejor de escribir esto? (Soy consciente del patrón de objeto nulo, pero parece excesivo usarlo para reemplazar estas cuatro líneas de código).
c#
code-smell
null
Ben Fulton
fuente
fuente
??!
es un operador en C ++. :-)Respuestas:
Tengo muchas ganas de una función de lenguaje C # que me permita hacer x.Prop.SomeOtherProp.ThirdProp de forma segura sin tener que verificar que ninguno de ellos sea nulo. En una base de código donde tenía que hacer mucho ese tipo de "recorridos de propiedades profundas", escribí un método de extensión llamado Navigate que tragaba NullReferenceExceptions y en su lugar devolvía un valor predeterminado. Entonces podría hacer algo como esto:
La desventaja de esto es que tiene un olor a código diferente: excepciones tragadas. Si desea hacer algo como esto "correcto", puede tomar la lamdba como una expresión y modificar la expresión sobre la marcha para agregar las comprobaciones nulas alrededor de cada acceso de propiedad. Fui por "rápido y sucio" y no lo implementé de esta manera "mejor". Pero tal vez cuando tenga algunos ciclos de pensamiento adicionales, vuelva a visitar esto y lo publique en alguna parte.
Para responder más directamente a su pregunta, supongo que la razón por la que esto no es una función es porque el costo de implementar la función excede el beneficio de tenerla. El equipo de C # tiene que elegir en qué características enfocarse, y esta todavía no ha llegado a la cima. Solo una suposición, aunque no tengo ninguna información privilegiada.
fuente
Creo que ahora podrás hacer esto con C # 6 de manera bastante simple:
Tenga en cuenta el operador condicional nulo
?.
en el lado izquierdo._mywidget?.Length
devuelve nulo si_mywidget
es nulo.Sin embargo, un operador ternario simple podría ser más fácil de leer, como otros han sugerido.
fuente
Realmente es solo una especulación de por qué no lo hicieron. Después de todo, no lo creo. estaba en la primera versión de C #.
De todos modos, simplemente usaría el operador condicional y lo llamaría un día:
Los ?? es solo un acceso directo al operador condicional.
fuente
5
como respuesta en caso de que no esté allí. Debe mirar su diseño antes de comenzar a solicitar operadores especiales.Se parece al operador ternario:
fuente
Personalmente, creo que se debe a la legibilidad. En el primer ejemplo, se
??
traduce bastante bien como "¿Estás ahí? No, hagamos esto".En el segundo ejemplo,
??!
es claramente WTF y no significa nada para el programador ... el objeto no existe, por lo que no puedo acceder a la propiedad, así que devolveré 5. ¿Qué significa eso? ¿Qué es 5? ¿Cómo llegamos a la conclusión de que 5 es un buen valor?En resumen, el primer ejemplo tiene sentido ... no está allí, nuevo . En el segundo, está abierto a debate.
fuente
(foo() != ERROR)??!??! cerr << "Error occurred" << endl;
)5
. Realmente creo que hay más de un problema que tienes que hacer algo como esto, mientras que en tu primer ejemplo, la necesidad es bastante obvia, especialmente en cosas como los administradores de caché.Creo que la gente está demasiado atrapada en el "5" que está regresando ... tal vez 0 hubiera sido mejor :)
De todos modos, creo que el problema es que en
??!
realidad no es un operador independiente. Considere qué significaría esto:En ese caso, no tiene sentido: solo tiene sentido si el operando de la izquierda es un descriptor de acceso a la propiedad. O que tal esto:
Hay un descriptor de acceso a la propiedad allí, pero todavía no creo que tenga sentido (si
myWidget
es asínull
, ¿eso significa que no llamamosFoo()
en absoluto?) ¿O es solo un error?Creo que el problema es que simplemente no encaja tan naturalmente en el lenguaje como lo
??
hace.fuente
Alguien había creado una clase de utilidad que haría esto por usted. Pero no puedo encontrarlo. Lo que encontré fue algo similar en los foros de MSDN (mira la segunda respuesta).
Con un poco de trabajo, puede extenderlo para evaluar las llamadas a métodos y otras expresiones que la muestra no admite. También puede extenderlo para aceptar un valor predeterminado.
fuente
Entiendo de dónde vienes. Parece como si todos estuvieran envueltos alrededor del eje con el ejemplo que usted proporcionó. Si bien estoy de acuerdo en que los números mágicos son una mala idea, se utilizaría el equivalente de un operador nulo de carbón para ciertas propiedades.
Por ejemplo, tiene objetos vinculados a un mapa y desea que estén a la elevación adecuada. Los mapas DTED pueden tener agujeros en sus datos, por lo que es posible tener un valor nulo, así como valores en el rango de algo como -100 a ~ 8900 metros. Es posible que desee algo en la línea de:
El operador de reducción de carbón nula en este caso llenaría la altitud predeterminada si las coordenadas aún no estuvieran configuradas o si el objeto de coordenadas no pudiera cargar datos DTED para esa ubicación.
Veo esto como muy valioso, pero mi especulación sobre por qué no se hizo se limita a la complejidad del compilador. Puede haber algunos casos donde el comportamiento no sería tan predecible.
fuente
Cuando no estoy tratando con anidados profundamente, he usado esto (antes del operador de fusión nula introducido en C # 6). Para mí es bastante claro, pero tal vez sea porque estoy acostumbrado, a otras personas les puede resultar confuso.
Por supuesto, esto no siempre es aplicable, ya que a veces la propiedad a la que necesita acceder no se puede establecer directamente, o cuando la construcción del objeto en sí es costosa, entre otras razones.
Otra alternativa es usar el patrón NullObject . Defina una única instancia estática de la clase con valores predeterminados razonables, y use eso en su lugar.
fuente
Los números mágicos suelen tener mal olor. Si el 5 es un número arbitrario, entonces es mejor deletrearlo para que esté documentado más claramente. En mi opinión, una excepción sería si tiene una colección de valores que actúan como valores predeterminados en un contexto particular.
Si tiene un conjunto de valores predeterminados para un objeto, puede subclasificarlo para crear una instancia de singleton predeterminada.
Algo así como: return (myobj ?? default_obj) .Longitud
fuente
La propiedad de longitud generalmente es un tipo de valor, por lo que no puede ser nula, por lo que el operador de fusión nula no tiene sentido aquí.
Pero puede hacerlo con una propiedad que es un tipo de referencia, por ejemplo:
var window = App.Current.MainWindow ?? new Window();
fuente
He visto a alguien con una idea similar antes, pero la mayoría de las veces también querría asignar el nuevo valor al campo nulo, algo así como:
así que la idea era combinar la asignación
??
y=
en:Creo que esto tiene más sentido que usar un signo de exclamación.
Esta idea no es mía pero me gusta mucho :)
fuente
return _obj ?? new Class();
no hay necesidad del??=
aquí.