Zrobiłem trochę badań na ten temat, używając różnych metod, aby przypisać wartości do wartości zerowej int. Oto, co się stało, gdy zrobiłem różne rzeczy. Powinien wyjaśnić, co się dzieje. Pamiętaj: Nullable<something>
albo stenografia something?
jest strukturą, dla której kompilator wydaje się wykonywać wiele pracy, abyśmy mogli używać wartości zerowej, jakby to była klasa.
Jak zobaczycie poniżej, SomeNullable == null
i SomeNullable.HasValue
zawsze zwraca oczekiwane prawdziwe lub fałszywe. Chociaż nie pokazano poniżej, SomeNullable == 3
jest również poprawny (zakładając, że SomeNullable jest an int?
).
Podczas gdy SomeNullable.Value
dostaje nam błąd czasu wykonania, jeśli przypisaliśmy null
do SomeNullable
. Jest to w rzeczywistości jedyny przypadek, w którym wartości zerowe mogą sprawić nam problem, dzięki kombinacji przeciążonych operatorów, przeciążonychobject.Equals(obj)
metoda oraz optymalizacja kompilatora i małpia firma.
Oto opis jakiegoś kodu, który uruchomiłem, i jaki wynik wygenerował w etykietach:
int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Ok, spróbujmy następnej metody inicjalizacji:
int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
Wszystko tak samo jak poprzednio. Należy pamiętać, że inicjowanie za pomocą int? val = new int?(null);
, z pustym przekazanym do konstruktora, spowodowałoby błąd czasowy KOMPILACJA, ponieważ WARTOŚĆ obiektu zerowalnego NIE jest dopuszczalna. Tylko sam obiekt otoki może mieć wartość null.
Podobnie otrzymalibyśmy błąd czasu kompilacji z:
int? val = new int?();
val.Value = null;
nie wspominając, że i tak val.Value
jest to właściwość tylko do odczytu, co oznacza, że nie możemy nawet użyć czegoś takiego:
val.Value = 3;
ale znowu polimorficzne przeciążone niejawne operatory konwersji pozwalają nam na:
val = 3;
Nie musisz się jednak martwić o wieloskładnikowe, o ile działa dobrze? :)