¿Por qué este código es inválido en C #?

El siguiente código no se comstackrá:

string foo = "bar"; Object o = foo == null ? DBNull.Value : foo; 

Obtengo: Error 1 El tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre ‘System.DBNull’ y ‘string’

Para solucionar esto, debo hacer algo como esto:

 string foo = "bar"; Object o = foo == null ? DBNull.Value : (Object)foo; 

Este elenco parece inútil ya que esto es ciertamente legal:

 string foo = "bar"; Object o = foo == null ? "gork" : foo; 

Me parece que cuando las twigs ternarias son de tipos diferentes, el comstackdor no va a autoboxear los valores para el tipo de objeto … pero cuando son del mismo tipo, el autoboxing es automático.

En mi opinión, la primera statement debería ser legal …

¿Alguien puede describir por qué el comstackdor no permite esto y por qué los diseñadores de C # eligieron hacer esto? Creo que esto es legal en Java … Aunque no he verificado esto.

Gracias.

EDITAR: Estoy pidiendo una comprensión de por qué Java y C # manejan esto de manera diferente, lo que está sucediendo debajo de las escenas en C # que lo hacen inválido. Sé cómo usar ternario, y no busco una “mejor manera” de codificar los ejemplos. Entiendo las reglas de ternary en C #, pero quiero saber POR QUÉ …

EDITAR (Jon Skeet): Se eliminó la etiqueta de “autoboxing” ya que no está involucrado el boxeo en esta pregunta.

El comstackdor requiere que los tipos de segundo y tercer operandos sean iguales o que uno sea implícitamente convertible al otro. En su caso, los tipos son DBNull y cadena, ninguno de los cuales es implícitamente convertible a la otra. Lanzar cualquiera de ellos al objeto lo resuelve.

EDITAR: Parece que es legal en Java. Como se explica qué hacer cuando se trata de sobrecarga de métodos, no estoy seguro … Acabo de ver el JLS, y no está muy claro cuál es el tipo de condicional cuando hay dos referencias incompatibles tipos involucrados. La forma de trabajar de C # puede ser más irritante de vez en cuando, pero es más clara la OMI.

La sección relevante de la especificación de C # 3.0 es 7.13, el operador condicional:

El segundo y tercer operandos del operador?: Controlan el tipo de expresión condicional. Deje que X e Y sean los tipos del segundo y tercer operandos. Entonces,

  • Si X e Y son del mismo tipo, este es el tipo del condicional
  • De lo contrario, si existe una conversión implícita (§6.1) de X a Y, pero no de Y a X, entonces Y es el tipo de expresión condicional.
  • De lo contrario, si existe una conversión implícita (§6.1) de Y a X, pero no de X a Y, entonces X es el tipo de expresión condicional.
  • De lo contrario, no se puede determinar ningún tipo de expresión y se produce un error en tiempo de comstackción.

DBNull.Value devuelve tipo DBNull .

Quieres que el tipo sea una string .

Si bien la string puede ser null no puede ser un DBNull .

En su código, la statement a la derecha de los iguales se ejecuta antes de la asignación al objeto.

Básicamente si usas:

 [condition] ? true value : false value; 

En .Net, tanto las opciones verdaderas como las falsas deben ser implícitamente convertibles al mismo tipo, antes de lo que se les asigne.

Esto es el resultado de cómo C # se relaciona con la seguridad de tipo. Por ejemplo, lo siguiente es válido:

 string item = "item"; var test = item != null ? item : "BLANK"; 

C # 3 no admite tipos dynamics, entonces, ¿qué es prueba? En C # cada asignación es también una statement con un valor de retorno, por lo que aunque la construcción var es nueva en C # 3, la statement a la derecha de los iguales siempre tiene que resolverse a un solo tipo.

En C # 4 y superior, puede admitir explícitamente tipos dynamics, pero no creo que eso ayude aquí.

Por cierto, su código es un caso especial que no tiene que usar el operador condicional en absoluto. En cambio, el operador de fusión nula es más apropiado (pero aún requiere conversión):

 object result = (object)foo ?? DBNull.Value;