2011-12-02 17 views
20

Zauważyłem dziwny problem w kawałku kodu, w którym zapytanie SQL adhoc nie generowało oczekiwanego wyniku, mimo że jego parametry pasowały do ​​rekordów w źródle danych. Postanowiłem wprowadzić następujące wyrażenie testowy do natychmiastowego oknem:Dlaczego konstruktor nazwa/wartość SqlParameter traktuje 0 jako wartość null?

new SqlParameter("Test", 0).Value 

To dało wyniku null, która pozostawia mnie drapania moją głowę. Wygląda na to, że konstruktor SqlParameter traktuje zera jako wartości null. Poniższy kod daje prawidłowy wynik:

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

Czy ktoś może wyjaśnić to zachowanie? Czy jest to w jakiś sposób zamierzone? Jeśli tak, to raczej potencjalnie niebezpieczne ...

+0

Więcej informacji na ten temat: http://stackoverflow.com/questions/14224465/compiler-value-type-resolution-and-hardcoded-0-integer-values ​​ – RLH

Odpowiedz

24

Jak stwierdzono w documentation do tego konstruktora:

Po określeniu obiekt w parametrze wartości, SqlDbType to wynika z rodzaju Microsoft .NET Framework Obiektu.

Należy zachować ostrożność, korzystając z tego przeciążenia konstruktora SqlParameter, aby określić wartości parametrów całkowitych. Ponieważ to przeciążenie przyjmuje wartość typu Object, należy przekonwertować wartość całki na typ Object, gdy wartość wynosi zero, jak pokazuje poniższy przykład C#.

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

Jeśli nie wykonywać tej konwersji, kompilator zakłada, że ​​starają się wywołać przeciążenie SqlParameter(string, SqlDbType) konstruktora.

Po prostu dzwoniłeś do innego konstruktora, niż myślisz w swojej sprawie.

Powodem tego jest to, że C# umożliwia niejawnego konwersji w całkowitej dosłownym 0 do ENUM typu (które są tylko integralne typy poniżej) i jest ukryte konwersji powoduje konstruktora (string, SqlDbType) być lepiej odpowiada rozdzielczości przeciążenia niż konwersja boksu konieczna do konwersji int na object dla konstruktora (string, object).

To nigdy nie będzie problemem, jeśli zdać intzmienną, nawet jeżeli wartość tej zmiennej jest 0 (bo nie jest to dosłowne zerowy) lub jakiekolwiek inne wyrażenie, które ma typ int. Nie stanie się tak również wtedy, gdy wyraźnie odrzucisz int do object, jak pokazano powyżej, ponieważ wtedy jest tylko jeden pasujący przeciążenie.

+0

Miałem ten problem i próbowałem innego rozwiązania, które nie działa: Dlaczego proponowany parametr "Parametr = nowy SqlParameter (" @ pname ", Convert.ToInt32 (0)); działa, gdy parametr" Parameter = new SqlParameter "(" @ pname ", (int) 0); Próbowałem, nie? – mortb

+0

@mortb, musisz sprawdzić specyfikację językową, ale domyślam się, że rozdzielczość przeciążenia będzie wymagać dokładnego typu w pierwszym przypadku, ale może pozwolić na wyliczenie w drugim, ponieważ nadal podajesz literał wpisz 'int'. – Joey

+0

Dowiedziałem się, dlaczego: http://stackoverflow.com/questions/3153841/strange-possibly-wrong-c-sharp-compiler-behavior-with-method-overloading- and Dosłowne 0 będzie zawsze oceniane jako pasuje do typu wyliczenia, podczas gdy inne numery nie. Wygląda trochę niejasno ... – mortb

5

Dobrze jest używać danych maszynowych podczas przekazywania/dodawania parametrów.

Poniżej sposób można wykonać zadanie jak poniżej:

STRING/varchar wpisywanych danych:

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

Dla int wpisywanych danych:

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

Można zmienić wartość SqlDbType zgodnie z używanymi danymi.

+0

Chociaż generalnie jest to pomocne, to technicznie nie jest to odpowiedź na pytanie. Powinien to być komentarz. – Joey

+2

@ Joey, tak masz rację, dziękuję za poświęcony czas. –

Powiązane problemy