2011-11-22 30 views
11

he encontrado C# comportamiento compilador muy extraño para siguiente código:Strange C Comportamiento # compilador (resolución de sobrecarga)

var p1 = new SqlParameter("@p", Convert.ToInt32(1)); 
    var p2 = new SqlParameter("@p", 1); 
    Assert.AreEqual(p1.Value, p2.Value); // PASS 

    var x = 0; 
    p1 = new SqlParameter("@p", Convert.ToInt32(x)); 
    p2 = new SqlParameter("@p", x); 
    Assert.AreEqual(p1.Value, p2.Value); // PASS 

    p1 = new SqlParameter("@p", Convert.ToInt32(0)); 
    p2 = new SqlParameter("@p", 0); 
    Assert.AreEqual(p1.Value, p2.Value); // FAIL!? 

En última aserción línea de falla con el siguiente mensaje:

Expected: 0 
    But was: null 

entiendo por qué la prueba falla: p2 = new SqlParameter("@p", 0); se resuelve como SqlParameter(string, SqlDbType) y para otros casos como SqlParameter(string, object). Pero no entiendo por qué sucede esto. Para mí, parece un error, pero no puedo creer que el compilador de C# pueda tener ese tipo de error.

Cualquier razones para esto?

P.S. Parece ser un problema para cualquier método de sobrecarga con el parámetro enum y el valor 0 (SqlDbType es enum).

Respuesta

11

Básicamente, el número entero decimal literal 0 es implícitamente convertible a todos los tipos enum (SPEC C# 4 §6.1.3), por lo que el compilador determina que SqlParameter(string, SqlDbType) es un miembro de la función aplicable. Entonces tiene que elegir el mejor entre dos candidatos funcionan miembros, y recoge SqlParameter(string, SqlDbType) sobre SqlParameter(string, object), porque SqlDbType es un tipo más específico que object (§7.5.3.2).

Pero estoy de acuerdo que en ese caso es muy confuso ...

+0

Sólo una idea, lo que sucede cuando se ajusta el nivel de advertencia al máximo? Quizás advierta sobre eso en este caso. – dowhilefor

+0

Yeap, lo tengo. Mi pregunta es: ¿por qué funciona solo para 0? –

+5

@VictorHaydin, debido a que la especificación dice así ... "Una conversión de enumeración implícita permite que el decimal-literal-entero de 0 a convertir en cualquier tipo de enumeración y para cualquier tipo anulable cuyo tipo subyacente es un tipo enum". Ahora, no sé por qué fue diseñado de esta manera, pero probablemente haya una buena razón ... debes preguntarle a alguien del equipo de C#. –

Cuestiones relacionadas