2011-11-22 21 views
11

Znalazłem bardzo dziwny C# zachowanie kompilatora dla następującego kodu:Strange C zachowanie # kompilator (rozdzielczość przeciążenie)

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!? 

W ostatniej linii assert nie powiedzie się z następującym komunikatem:

Expected: 0 
    But was: null 

rozumiem dlaczego test kończy się niepowodzeniem: p2 = new SqlParameter("@p", 0); został rozwiązany jako SqlParameter(string, SqlDbType), a w innych przypadkach jako SqlParameter(string, object). Ale nie rozumiem, dlaczego tak się dzieje. Dla mnie wygląda jak błąd, ale nie mogę uwierzyć, że kompilator C# mógłby mieć taki błąd.

Jakiekolwiek powody tego?

P.S. Wydaje się, że jest to problem dla każdej metody przeciążenia z parametrem enum i wartością 0 (SqlDbType jest enum).

Odpowiedz

11

Zasadniczo, liczba całkowita dosłownym 0 niejawnie zamienny dla wszystkich typów wyliczeń (C 4 Spec §6.1.3) tak, że kompilator stwierdzi SqlParameter(string, SqlDbType) jest zastosowanie element funkcyjny. Następnie musi wybrać lepszy stosunek pomiędzy dwoma kandydatami na członków funkcji i wybiera SqlParameter(string, SqlDbType) przez SqlParameter(string, object), ponieważ SqlDbType jest typem bardziej szczegółowym niż object (§7.3.3.2).

Ale zgadzam się, że w tym przypadku jest to bardzo mylące ...

+0

Po prostu pomysł, co się stanie, gdy poziom ostrzeżenia zostanie ustawiony na maksimum? Może ostrzeże to w tym przypadku. – dowhilefor

+0

Yeap, mam to. Moje pytanie brzmi: dlaczego działa tylko dla 0? –

+5

@VictorHaydin, ponieważ specyfikacja mówi tak ... "Niejawna konwersja wyliczeń umożliwia przekształcenie liczby całkowitej dziesiętnej w liczbę całkowitą 0 na dowolny typ wyliczeniowy i dowolny typ zerowy, którego podstawowym typem jest typ wyliczeniowy". Teraz nie wiem, dlaczego został zaprojektowany w ten sposób, ale jest prawdopodobnie dobry powód ... musisz zapytać kogoś z zespołu C#. –