2012-06-01 22 views
15

Tengo el siguiente bit de código para establecer un parámetro que se utilizará en una instrucción INSERT para establecer una columna VARCHAR en una base de datos SQL Server. Mi objeto de valor (llamado ilo) tiene una propiedad llamada Descripción que se inicializa en String.Empty, y luego se establece en algún valor leído desde XML, o si ese elemento XML está vacío, simplemente permanece como String.Empty.Configurando el parámetro a DBNull.Value usando la sintaxis ternaria da error?

De modo que cuando inserte en la base de datos, si la propiedad todavía está configurada en String.Empty, me gustaría que inserte un valor nulo.

database.AddInParameter(cmd, "@description", DbType.String, 
          (ilo.Description.Equals(string.Empty)) ? 
          DBNull.Value : 
          ilo.Description); 

Así que básicamente lo que digo, si es igual ilo.Description String.Empty, establezca el parámetro en DBNull.Value, de lo contrario la puso a ilo.Description.

Esto da el siguiente error en Visual Studio ...

Error 141 Tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre 'System.DBNull' y 'cadena'

¿Por qué?

La parte curiosa es que puedo hacer lo siguiente sin ningún error, ¡que debería ser exactamente lo mismo que usar la sintaxis condicional en línea como la de arriba!?!

if(ilo.Description.Equals(string.Empty)) 
{ 
    database.AddInParameter(cmd, "@description", DbType.String, DBNull.Value); 
} 
else 
{ 
    database.AddInParameter(cmd, "@description", DbType.String, ilo.Description); 
} 

Busqué en otras publicaciones, y encontré la siguiente, pero en realidad no responde mi pregunta.

EntLib Way to Bind "Null" Value to Parameter

Estoy más interesado en saber por qué, debido a que la solución obvia es usar un else if/en lugar de la sintaxis en línea (ternaria)?

Hay una especie de respuesta en este enlace, pero me gustaría una mejor explicación porque parece ser BS para mí que esto no funciona; ¡Lo llamaría un error!

http://msdn.microsoft.com/en-us/library/ty67wk28.aspx

+1

Puede obtener detalles sobre el operador ternario y este tipo de problema [en esta respuesta] (http://stackoverflow.com/questions/4290203/simple-c-why-assigning-null-in-ternary-operator-fails -no-implicit-conversion) – Steve

+0

Gracias Steve. Su enlace era lo que estaba buscando realmente. Creo que este es un aspecto estúpido de .NET; ¿Por qué no solo evalúan si los tipos de cada resultado posible se ajustan a la afirmación? es decir, si dices Object o = (someBool)? someInt32: someString; se obtiene un error, pero ¿qué tan fácil sería evaluar que ambos resultados se pueden convertir implícitamente a un objeto, en lugar de evaluar si alguna cadena se puede convertir en algunaInt32? Me parece estúpido, pero supongo que así es. ¡Gracias! – Jim

+0

También me gustaría comentar que estoy muy impresionado con la velocidad y la precisión de las respuestas a este hilo. ¡Esta comunidad es increíble! ¡Gracias a todos! – Jim

Respuesta

34

Este es un error común de personas reciben cuando se utiliza el operador condicional. Para solucionarlo, simplemente arroje uno o ambos resultados a un tipo de base común.

ilo.Description.Equals(string.Empty) 
    ? (object)DBNull.Value 
    : ilo.Description 

El problema se revela en el mensaje de error que vio.

Tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre 'System.DBNull' y 'cadena'

Una cadena no es un DBNull, y una DBNull no es una cadena. Por lo tanto, el compilador no puede determinar el tipo de la expresión. Al usar un molde para un tipo de base común (en este caso, object), crea un escenario donde el compilador puede determinar que esa cadena también es convertible a objeto, por lo que el tipo de expresión se puede determinar como un objeto, que también es muy útil encaja con lo que su línea de código también espera como el argumento DbParameter.

+0

El comentario de Steve da un enlace con más detalles, pero tu respuesta también es muy correcta. Me parece tonto tener que hacer eso. Creo que en Java esto no sucede. – Jim

1

Obtiene el error de compilación porque ambas partes de la expresión ternaria deben ser del mismo tipo.La solución más sencilla para esta situación particular es para echar tanto a un objeto:

database.AddInParameter(cmd, "@description", DbType.String, 
          (ilo.Description.Equals(string.Empty)) ? 
          (object) DBNull.Value : 
          (object) ilo.Description); 
+0

Como sugirió lazyberezovsky, también es mejor usar null en lugar de DBNull.Value aquí. Creo que solo necesita usar DBNull.Value al leer desde un lector de datos o un conjunto de datos. – Tuan

2

Anthony es de hecho correcta por lo que debe obtener la respuesta correcta, sin embargo aquí es un método de extensión, porque estoy aburrido ...

public static object NullCheck(this string self) 
    { 
     return (string.IsNullOrEmpty(self)) ? (object)DBNull.Value : self; 
    } 

uso en su escenario:

database.AddInParameter(cmd, "@description", DbType.String, 
          ilo.Description.NullCheck()); 
+0

cosas buenas. Aunque probablemente no use este método, solo me enseñó algunas cosas sobre C# que no sabía antes; como si ni siquiera notara el método IsNullOrEmpty en String antes. Estoy muy acostumbrado a Java y estoy contento de aprender más C#. ¡Gracias! – Jim

+0

No hay que preocuparse, después de pensarlo, sería mejor poner el método de extensión en el objeto ParameterCollection/database en sí para proporcionar un contenedor que maneje nulos de la manera que desee. – Marlon

4

Esto es lo que he encontrado en otro hilo y funcionó muy bien para mí:

yourVariable ?? (object)DBNull.Value 

Espero que ayude.

Cuestiones relacionadas