2011-12-02 11 views
20

Observé un problema extraño en un fragmento de código donde una consulta adhoc SQL no producía el resultado esperado, aunque sus parámetros coincidían con los registros en la fuente de datos. Decidí entrar en la expresión de prueba siguiente en la ventana inmediata:¿Por qué el constructor de nombre/valor SqlParameter trata 0 como nulo?

new SqlParameter("Test", 0).Value 

Se obtuvo un resultado de null, lo que me deja rascándome la cabeza. Parece que el constructor SqlParameter trata los ceros como nulos. El siguiente código produce el resultado correcto:

SqlParameter testParam = new SqlParameter(); 
testParam.ParameterName = "Test"; 
testParam.Value = 0; 
// subsequent inspection shows that the Value property is still 0 

¿Alguien puede explicar este comportamiento? ¿Es de alguna manera intencional? Si es así, es potencialmente bastante peligroso ...

+0

Lectura adicional sobre este tema: http://stackoverflow.com/questions/14224465/compiler-value-type-resolution-and-hardcoded-0-integer-values ​​ – RLH

Respuesta

24

Como se indica en la documentation de ese constructor:

Cuando se especifica un objeto en el parámetro de valor, el SqlDbType se infiere a partir del tipo de Microsoft .NET Framework del objeto

Tenga cuidado cuando use esta sobrecarga del constructor SqlParameter para especificar valores de parámetros enteros. Debido a que esta sobrecarga toma un valor de tipo Object, debe convertir el valor integral a Object cuando el valor es cero, como lo demuestra el siguiente ejemplo de C#.

Parameter = new SqlParameter("@pname", (object)0); 

Si no se realiza esta conversión, el compilador asume que usted está tratando de llamar a la sobrecarga de SqlParameter(string, SqlDbType) constructor.

Simplemente llamaba a un constructor diferente de lo que pensaba en su caso.

La razón de esto es que C# permite un implícita conversión del literal entero 0 es posible enumerar los tipos (que son tipos simplemente integrales debajo), y esta conversión implícita hace que el constructor (string, SqlDbType) ser un mejor partido para la resolución de sobrecarga que la conversión de boxeo necesaria para convertir int en object para el constructor (string, object).

esto nunca va a ser un problema cuando se pasa un int variables, incluso si el valor de esa variable es 0 (porque no es un literal cero), o cualquier otra expresión que tiene el tipo int. Tampoco ocurrirá si expulsa explícitamente int a object como se ve arriba, porque entonces solo hay una sobrecarga coincidente.

+0

Estaba teniendo este problema e intenté una solución diferente que no funcionó: ¿Por qué el 'Parámetro = nuevo parámetro SqlParameter propuesto (" @ pname ", Convert.ToInt32 (0));' funciona cuando 'Parameter = new SqlParameter (" @ pname ", (int) 0);' que Lo intenté, ¿no? – mortb

+0

@mortb, tendrías que consultar las especificaciones de idioma para eso, pero mi conjetura sería que la resolución de sobrecarga importaría el tipo exacto en el primer caso pero podría permitir enumeraciones en el segundo porque todavía estás pasando un literal de tipo 'int'. – Joey

+0

He descubierto por qué: http://stackoverflow.com/questions/3153841/strange-possibly-wrong-c-sharp-compiler-behavior-with-method-overloading-and El literal 0 siempre se evaluará como coincidiendo con el tipo de una enumeración, mientras que otros números no lo harán. Parece un poco oscuro ... – mortb

5

Es una buena práctica usar datos tipeados mientras pasa/agrega sus parámetros.

A continuación manera se puede realizar la tarea de la siguiente manera:

Para la secuencia/varchar datos a máquina:

SqlParameter pVarchar = new SqlParameter 
        { 
         ParameterName = "Test", 
         SqlDbType = System.Data.SqlDbType.VarChar, 
         Value = string.Empty, 
        }; 

Para int datos mecanografiados:

SqlParameter pInt = new SqlParameter 
        { 
         ParameterName = "Test", 
         SqlDbType = System.Data.SqlDbType.Int, 
         Value = 0, 
        }; 

Puede cambiar el valor de SqlDbType según sus datos usados.

+0

Aunque generalmente es útil, esto técnicamente no es una respuesta a la pregunta. Por lo tanto, debe ser un comentario. – Joey

+2

@Joey, sí, tienes razón, gracias por tu tiempo. –

Cuestiones relacionadas