Ternaria VB operador vs C #: ¿por qué no resuelve nada a cero?
-
30-09-2019 - |
Pregunta
acabo de pegarme un tiro en el pie y me gustaría saber si hay razones reales para hacer posible esta situación.
Y de todos modos, esta pregunta puede permanecer para la comodidad de los tiradores del pie futuro.
Supongamos que tenemos un valor anulable en vb.net:
Dim i as Integer?
Queremos asignar un valor a la misma, basándose en una condición, y el uso de un operador ternario, porque es muy limpio y esas cosas:
i = If(condition(), Nothing, 42)
Es decir, si una condición es true
, recurrir a la capacidad de nulos, de lo contrario el valor.
Momento en el que se produce el disparo. Sin razón aparente compilador de VB decide que el tipo base común para Nothing
y Integer
es Integer
, en cuyo punto se traduce en silencio a la declaración:
i = If(condition(), 0, 42)
Ahora, si tuviera que hacer esto en C #:
i = (condition()) ? null : 42;
obtendría inmediatamente un error de compilación diciendo que <null>
no se combina bien con int
. Lo cual es genial, ya que mi pie habría sido más saludable tenían fui el C # forma en este momento. Y para que esto compilar, usted tiene que escribir explícitamente:
i = (condition()) ? null : (int?)42;
Ahora, puede hacer lo mismo en VB y obtener la correcta nula-dad que se puede esperar:
i = If(condition(), Nothing, CType(42, Integer?))
Pero eso requiere tener su toma pie en el primer lugar. No hay error de compilación y no hay ninguna advertencia. Que de con Explicit On
y Strict On
.
Así que mi pregunta es, ¿por qué?
¿Debo tomar esto como un error del compilador?
O puede alguien explicar por qué el compilador se comporta de esta manera?
Solución
Esto se debe a Nothing
de VB no es un equivalente directo a null
C # 's.
Por ejemplo, en C # este código no se compilará:
int i = null;
Sin embargo, este código VB.Net funciona bien:
Dim i As Integer = Nothing
de VB.Net Nothing
es en realidad una aproximación más exacta para la expresión default(T)
C # 's.
Otros consejos
El operador ternario sólo puede devolver un tipo.
En C #, pero intenta elegir un tipo basado en null
y 42
. Bueno, null
no tiene un tipo, por lo que decide que el tipo de retorno del operador ternario es el de 42
; int
un simple y llano. A continuación, se queja porque no se puede devolver null como un viejo int
llanura. Al obligar a 42 como int?
, el operador ternario va a devolver un int?
, por lo que de null
válida.
Ahora, no sé sobre VB, pero citando el MSDN, España
Assigning Nothing to a variable sets it to the default value for its declared type.
que, desde VB determina que el operador ternario devolverá un int
(utilizando el mismo proceso C # DID), Nothing
es 0
. Una vez más, coaccionando el 42
a ser un int?
Nothing
se convierte en el valor predeterminado de int?
, que es null
, como se esperaba.
Estoy pensando que esto tiene algo que ver con SI que con nada. Considere este código:
''# This raises an exception
Dim x As Integer?
x = If(True, Nothing, Nothing)
MessageBox.Show(x.Value)
''# As does
Dim x As Integer?
x = Nothing
MessageBox.Show(x.Value)
''# Changing one of the truthpart arguments of If is what seems to return the zero.
Dim x As Integer?
x = If(True, Nothing, 5)
MessageBox.Show(x.Value)
¿Por qué está haciendo esto todavía no sé, probablemente, una pregunta para el equipo de VB. No creo que esto tiene que ver con la palabra clave Nada o anulable.
Nothing
y null
no son la misma cosa ... desde el MSDN:
Nada Asignación a una variable lo establece en el valor predeterminado para su tipo declarado.
también
Si proporciona un tipo de valor en la expresión, IsNothing siempre devuelve Falso.
Tenga en cuenta que int? es un tipo anulable, pero aún así es un tipo de valor, no un tipo de referencia.
Inténtelo de DbNull.Value
al lugar de Nothing
...
En una serie de casos Nothing
conseguirá convertido en el valor predeterminado. Para uso Nothing
la misma manera que utilizaría null
lo que necesita para su emisión al tipo anulable correcta.
Dim str As String
Dim int As Nullable(Of Integer) ' or use As Integer?
Dim reader As SqlDataReader
Dim colA As Integer = reader.GetOrdinal("colA")
Dim colB As Integer = reader.GetOrdinal("colB")
str = If(reader.IsDBNull(colA), DirectCast(Nothing, String), reader.GetString(colA))
int = If(reader.IsDBNull(colB), DirectCast(Nothing, Nullable(Of Integer)), reader.GetInt32(colB))
Esto sucede porque Entero no es un tipo de referencia. 'Nada' se supone que sólo el trabajo de los tipos de referencia. Para los tipos de valor asignación Nada se convierte automáticamente en el valor predeterminado, que es en el caso de un número entero 0.
Esto es realmente posible ahora en VS2015 (por lo menos) mediante el uso de Nueva entero?
Ej .:
Si (testInt> 0, testInt, Nueva entero?), Donde testInt es de tipo entero?