Operador ternario VB vs C #: ¿por qué no resuelve nada a cero?

Me pegué un tiro en el pie y me gustaría saber si hay razones reales para que esta situación sea posible.
Y de todos modos, esta pregunta puede permanecer para la conveniencia de los futuros tiradores de pies.


Supongamos que tenemos un valor anulable en vb.net:

Dim i as Integer? 

Queremos asignarle un valor, basándonos en una condición y utilizando un operador ternario, porque es muy claro y eso:

 i = If(condition(), Nothing, 42) 

Es decir, si una condición es true , emplee la capacidad de anulación, de lo contrario, el valor.
En ese punto ocurre el disparo. Sin ninguna razón aparente, el comstackdor de VB decide que el tipo de base común para Nothing e Integer es Integer , en cuyo punto traduce silenciosamente el enunciado a:

 i = If(condition(), 0, 42) 

Ahora, si hicieras esto en C #:

 i = (condition()) ? null : 42; 

Inmediatamente obtendría un error de comstackción que dice que no se combina bien con int . Lo cual es genial, ya que mi pie habría estado más sano si hubiera elegido el modo C # esta vez. Y para que esto compile, debes escribir explícitamente:

 i = (condition()) ? null : (int?)42; 

Ahora, puedes hacer lo mismo en VB y obtener la nulidad correcta que esperarías:

 i = If(condition(), Nothing, CType(42, Integer?)) 

Pero eso requiere tener tu pie en primer lugar. No hay error de comstackción y no hay advertencia. Eso es con Explicit On y Strict On .


¿Mi pregunta es, porque?
¿Debo tomar esto como un error de comstackción?
¿O alguien puede explicar por qué el comstackdor se comporta de esta manera?

Esto se debe a que Nothing de VB Nothing es un equivalente directo al null C #.

Por ejemplo, en C # este código no se comstackrá:

 int i = null; 

Pero este código de VB.Net funciona bien:

 Dim i As Integer = Nothing 

El Nothing de VB.Net en realidad es una coincidencia más cercana para la expresión default(T) de C #.

El operador ternario solo puede devolver un tipo.

En C #, 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 ; un simple antiguo int . Entonces se queja porque no se puede devolver nulo como un simple antiguo int . Cuando coaccionas 42 como int? , el operador ternario va a devolver un int? , por lo tanto null es válido.

Ahora, no sé acerca de VB, pero citando de MSDN,
Assigning Nothing to a variable sets it to the default value for its declared type.

Que, dado que VB determina que el operador ternario devolverá un int (usando el mismo proceso que C # hizo), Nothing es 0 . De nuevo, forzando al 42 a ser un int? convierte Nothing en el valor predeterminado de int? , que es null , como esperabas.

Estoy pensando que esto tiene algo más que ver con SI que con Nada. Considera 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 lo sé, probablemente sea una pregunta para el equipo de VB. No creo que tenga que ver con la palabra clave Nothing o Nullable.

Nothing y null no son lo mismo … de MSDN:

Al asignar Nothing a una variable, se establece en el valor predeterminado para su tipo declarado.

también

Si proporciona un tipo de valor en Expresión, IsNothing siempre devuelve False.

Tenga en cuenta que int? es un tipo anulable, pero sigue siendo un tipo de valor, no un tipo de referencia.

Intente configurarlo en DbNull.Value lugar de Nothing

En algunos casos, Nothing se convertirá al valor predeterminado. Para usar Nothing la misma forma que usaría null , debe convertirlo al tipo correcto de nulos.

 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 Integer no es un tipo de referencia. Se supone que ‘Nothing’ solo funciona para los tipos de referencia. Para los tipos de valor que asignan Nada se convierte automáticamente al valor predeterminado, que es en el caso de un Entero 0.

¿Esto es realmente posible ahora en VS2015 (al menos) usando New Integer?

Ex.:

If (testInt> 0, testInt, New Integer?), Donde testInt es de tipo Integer?