¿Cuál es el comportamiento deseado cuando v1es null?
Solomon Ucko
Respuestas:
637
Las otras respuestas hasta ahora son todas correctas; Solo quería agregar uno más que sea un poco más limpio:
v2 = v1 ??default(int);
Cualquiera Nullable<T>es implícitamente convertible a su T, SIEMPRE que la expresión completa que se evalúa nunca puede dar como resultado una asignación nula a un ValueType. Entonces, el operador de fusión nula ??es solo azúcar de sintaxis para el operador ternario:
v2 = v1 ==null?default(int): v1;
... que a su vez es sintaxis de azúcar para un if / else:
if(v1==null)
v2 =default(int);else
v2 = v1;
Además, a partir de .NET 4.0, Nullable<T>tiene un método "GetValueOrDefault ()", que es un getter nulo seguro que básicamente realiza la fusión nula que se muestra arriba, por lo que esto también funciona:
¿Es default(int)realmente necesario? ¿Qué tiene de malo un simple 0?
Cole Johnson
44
Funcionaría para este ejemplo, pero en el caso general se recomienda usar defaultdonde sea apropiado. El cero no siempre es válido como valor, mucho menos el predeterminado, por lo que si lo reemplaza intcon un genérico T, encontrará que mi código funciona mientras que el cero no. En algunas versiones futuras del framework, defaulttambién puede volverse sobrecargable; si eso sucede, el código que usa el valor predeterminado podrá aprovechar fácilmente, mientras que las asignaciones explícitas nulas o nulas tendrán que cambiarse.
KeithS
55
Esto debería llegar a la cima: .NET 4.0, Nullable <T> tiene un "GetValueOrDefault ()"
RandomHandle
¡Gracias por volver a editarlo con GetValueOrDefault!
CindyH
Es posible que desee tener cuidado con DateTime cuando usa el valor predeterminado. Esto podría insertar la fecha predeterminada en lugar de vacía.
Además, si no está seguro de si v1 contiene nulo, puede usar el operador de fusión nula para establecer un valor de reserva. Por ejemplo, v2 = v1 ?? 0;
Arjen
12
Y asegúrese de verificar v1.HasValueprimero.
Yuck
3
MSDN dice que esto arrojará una excepción si v1es así null. En mi opinión, esta no es una respuesta correcta.
ventiseis
66
@ventiseis Creo que es un comportamiento deseable: me sorprende que muchas de las otras respuestas estén bien con la conversión silenciosa de un valor nulo a 0. Si está asignando un tipo anulable a un tipo no anulable, debe estar seguro de que el valor no es realmente nulo. OP no dijo "Quiero asignar v1 a v2, o 0 si v1 es nulo", pero eso es lo que todos parecían asumir
Si sabe que v1tiene un valor, puede usar la Valuepropiedad:
v2 = v1.Value;
El uso del GetValueOrDefaultmétodo asignará el valor si hay uno; de lo contrario, el valor predeterminado para el tipo o el valor predeterminado que especifique:
v2 = v1.GetValueOrDefault();// assigns zero if v1 has no value
v2 = v1.GetValueOrDefault(-1);// assigns -1 if v1 has no value
Puede usar la HasValuepropiedad para verificar si v1tiene un valor:
if(v1.HasValue){
v2 = v1.Value;}
También hay soporte de idioma para el GetValueOrDefault(T)método:
Una conversión simple entre v1y v2no es posible porque v1tiene un dominio de valores mayor que v2. Es todo lo que v1puede aguantar más el nullestado. Para realizar la conversión, debe indicar explícitamente qué valor intse utilizará para asignar el nullestado. La forma más simple de hacer esto es el ??operador
v2 = v1 ??0;// maps null of v1 to 0
Esto también se puede hacer en forma larga
int v2;if(v1.HasValue){
v2 = v1.Value;}else{
v2 =0;}
Dependiendo de su contexto de uso, puede usar la función de coincidencia de patrones de C # 7:
int? v1 =100;if(v1 isint v2){Console.WriteLine($"I'm not nullable anymore: {v2}");}
EDITAR:
Dado que algunas personas están votando sin dejar una explicación, me gustaría agregar algunos detalles para explicar la justificación para incluir esto como una solución viable.
La coincidencia de patrones de C # 7 ahora nos permite verificar el tipo de un valor y emitirlo implícitamente. En el fragmento anterior, la condición if solo pasará cuando el valor almacenado v1sea compatible con el tipo para el tipo v2, que en este caso lo es int. Se deduce que cuando el valor para v1es null, la condición if fallará ya que nulo no puede asignarse a un int. Más adecuadamente, nullno es un int.
Me gustaría destacar que esta solución puede no ser siempre la mejor opción. Como sugiero, creo que esto dependerá del contexto de uso exacto del desarrollador. Si ya tiene un int?y desea operar condicionalmente en su valor si y solo si el valor asignado no es nulo (este es el único momento en que es seguro convertir un int anulable en un int regular sin perder información), entonces La coincidencia de patrones es quizás una de las formas más concisas de hacer esto.
La necesidad de introducir un nuevo nombre de variable es lamentable, pero esta es la mejor solución (la más segura) si no hay un valor predeterminado, porque no hay riesgo de refactorizar accidentalmente sus HasValuecheques.
minexew
Simplemente no veo ninguna ventaja para este método sobre v1.HasValue como la comprobación y luego v1.Value para acceder al valor subyacente. No lo rechazaría, pero creo que este problema ya se ha resuelto y una nueva técnica no agrega mucha claridad al problema. También lo comparé como 8-9% más lento.
Brandon Barkley
Gracias por compararlo, ¡es bueno saberlo! De cualquier manera que lo mire, la diferencia es marginal en el mejor de los casos (a menos que haga esto en un área crítica, supongo). Considero que esto es más "conciso" o posiblemente "idiomático", ya que se basa en azúcares de sintaxis en el lenguaje en lugar de API. Es un poco subjetivo, pero quizás sea "más fácil de mantener". Aunque realmente, me gusta este enfoque más que confiar en un valor predeterminado, como sugieren muchas otras respuestas.
Nicholas Miller
3
Asignará el valor de v1a v2si no es nulo, de lo contrario tomará un valor predeterminado como cero.
En C # 7.1 y versiones posteriores, se puede inferir el tipo usando el defaultliteral en lugar del defaultoperador para que se pueda escribir de la siguiente manera:
Si bien este código puede responder la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo responde la pregunta mejora su valor a largo plazo.
Al contestar una pregunta de ocho años con quince respuestas existentes, es importante explicar qué nuevo aspecto de la pregunta aborda su respuesta y observar si el paso del tiempo ha cambiado la respuesta. Las respuestas de solo código casi siempre se pueden mejorar mediante la adición de alguna explicación.
v1
esnull
?Respuestas:
Las otras respuestas hasta ahora son todas correctas; Solo quería agregar uno más que sea un poco más limpio:
Cualquiera
Nullable<T>
es implícitamente convertible a suT
, SIEMPRE que la expresión completa que se evalúa nunca puede dar como resultado una asignación nula a un ValueType. Entonces, el operador de fusión nula??
es solo azúcar de sintaxis para el operador ternario:... que a su vez es sintaxis de azúcar para un if / else:
Además, a partir de .NET 4.0,
Nullable<T>
tiene un método "GetValueOrDefault ()", que es un getter nulo seguro que básicamente realiza la fusión nula que se muestra arriba, por lo que esto también funciona:fuente
default(int)
realmente necesario? ¿Qué tiene de malo un simple0
?default
donde sea apropiado. El cero no siempre es válido como valor, mucho menos el predeterminado, por lo que si lo reemplazaint
con un genéricoT
, encontrará que mi código funciona mientras que el cero no. En algunas versiones futuras del framework,default
también puede volverse sobrecargable; si eso sucede, el código que usa el valor predeterminado podrá aprovechar fácilmente, mientras que las asignaciones explícitas nulas o nulas tendrán que cambiarse.Me gusta esto,
fuente
Puede usar la propiedad Value para la asignación.
fuente
v1.HasValue
primero.v1
es asínull
. En mi opinión, esta no es una respuesta correcta.Todo lo que necesitas es..
fuente
Si sabe que
v1
tiene un valor, puede usar laValue
propiedad:El uso del
GetValueOrDefault
método asignará el valor si hay uno; de lo contrario, el valor predeterminado para el tipo o el valor predeterminado que especifique:Puede usar la
HasValue
propiedad para verificar siv1
tiene un valor:También hay soporte de idioma para el
GetValueOrDefault(T)
método:fuente
No puede hacerlo si v1 es nulo, pero puede verificarlo con un operador.
fuente
recupera el valor del objeto. Si es nulo, devuelve el valor predeterminado de int, que es 0.
Ejemplo:
fuente
Si el valor predeterminado para un tipo dado es un resultado aceptable:
Si desea un valor predeterminado diferente cuando el resultado no está definido:
Si solo desea que se devuelva el valor (no importa si el método falló o no):
.NET 4.7.2 .:
GetValueOrDefault()
devuelve el valor del campo sin ninguna comprobación.fuente
En lo que a mí respecta, la mejor solución es usar el
GetValueOrDefault()
método.fuente
La conversión de int nullable a int se puede hacer así:
fuente
es posible con
v2 = Convert.ToInt32(v1);
fuente
Podrías hacerlo
fuente
Una conversión simple entre
v1
yv2
no es posible porquev1
tiene un dominio de valores mayor quev2
. Es todo lo quev1
puede aguantar más elnull
estado. Para realizar la conversión, debe indicar explícitamente qué valorint
se utilizará para asignar elnull
estado. La forma más simple de hacer esto es el??
operadorEsto también se puede hacer en forma larga
fuente
Dependiendo de su contexto de uso, puede usar la función de coincidencia de patrones de C # 7:
EDITAR:
Dado que algunas personas están votando sin dejar una explicación, me gustaría agregar algunos detalles para explicar la justificación para incluir esto como una solución viable.
La coincidencia de patrones de C # 7 ahora nos permite verificar el tipo de un valor y emitirlo implícitamente. En el fragmento anterior, la condición if solo pasará cuando el valor almacenado
v1
sea compatible con el tipo para el tipov2
, que en este caso lo esint
. Se deduce que cuando el valor parav1
esnull
, la condición if fallará ya que nulo no puede asignarse a unint
. Más adecuadamente,null
no es unint
.Me gustaría destacar que esta solución puede no ser siempre la mejor opción. Como sugiero, creo que esto dependerá del contexto de uso exacto del desarrollador. Si ya tiene un
int?
y desea operar condicionalmente en su valor si y solo si el valor asignado no es nulo (este es el único momento en que es seguro convertir un int anulable en un int regular sin perder información), entonces La coincidencia de patrones es quizás una de las formas más concisas de hacer esto.fuente
HasValue
cheques.Asignará el valor de
v1
av2
si no es nulo, de lo contrario tomará un valor predeterminado como cero.O debajo está la otra forma de escribirlo.
fuente
En C # 7.1 y versiones posteriores, se puede inferir el tipo usando el
default
literal en lugar deldefault
operador para que se pueda escribir de la siguiente manera:fuente
fuente