Dlaczego to się nie kompiluje?
int? number = true ? 5 : null;
Nie można określić typu wyrażenia warunkowego, ponieważ nie ma niejawnej konwersji między „int” i <null>
Dlaczego to się nie kompiluje?
int? number = true ? 5 : null;
Nie można określić typu wyrażenia warunkowego, ponieważ nie ma niejawnej konwersji między „int” i <null>
Odpowiedzi:
Spec (§7.14) mówi, że dla wyrażenia warunkowego b ? x : y
, istnieją trzy możliwości, albo x
i y
obie mają typ i pewne warunki dobre są spełnione, tylko jeden x
i y
ma typ i pewne warunki dobre są spełnione, lub błąd czasu kompilacji występuje. Tutaj „pewne dobre warunki” oznaczają, że możliwe są pewne konwersje, które omówimy szczegółowo poniżej.
Teraz przejdźmy do podstawowej części specyfikacji:
Jeśli tylko jeden z
x
iy
ma typ, a obax
iy
są niejawnie konwertowane na ten typ, to jest to typ wyrażenia warunkowego.
Problem w tym, że w
int? number = true ? 5 : null;
tylko jeden z wyników warunkowych ma typ. Tutaj x
jest int
dosłowne, i y
to null
, które ma nie mieć typ i null
nie jest niejawnie zamienny do int
1 . Dlatego „pewne dobre warunki” nie są spełnione i pojawia się błąd w czasie kompilacji.
Można to obejść na dwa sposoby:
int? number = true ? (int?)5 : null;
Tutaj nadal jesteśmy w przypadku, gdy tylko jeden z x
i y
ma typ. Należy zauważyć, że null
nadal nie ma typ jeszcze kompilator nie będzie miał żadnego problemu z tego powodu (int?)5
i null
to zarówno w sposób dorozumiany do zamienny int?
(§6.1.4 i §6.1.5).
Drugi sposób to oczywiście:
int? number = true ? 5 : (int?)null;
ale teraz musimy przeczytać inną klauzulę w specyfikacji, aby zrozumieć, dlaczego jest to w porządku:
Jeśli
x
ma typX
iy
ma typY
to
Jeśli niejawna konwersja (§6.1) istnieje od
X
doY
, ale nie odY
doX
, toY
jest to typ wyrażenia warunkowego.Jeśli niejawna konwersja (§6.1) istnieje od
Y
doX
, ale nie odX
doY
, toX
jest to typ wyrażenia warunkowego.W przeciwnym razie nie można określić typu wyrażenia i wystąpi błąd w czasie kompilacji.
Tutaj x
jest typu int
i y
jest typu int?
. Nie ma niejawna konwersja od int?
celu int
, ale istnieje niejawna konwersja z int
do int?
tak typ wyrażenia jest int?
.
1 : Należy ponadto zauważyć, że typ lewej strony jest pomijany przy określaniu typu wyrażenia warunkowego, co jest tutaj częstym źródłem nieporozumień.
new int?()
na miejscu (int?)null
.
DateTime
, gdy jest to wymagane(DateTime?)
null
nie ma żadnego rozpoznawalnego typu - wystarczy trochę popchnąć, aby był szczęśliwy:
int? number = true ? 5 : (int?)null;
int? number = true ? 5 : null as int?;
int? number = true ? 5 : (int?)null;
i int? number = true ? (int?)5 : null;
oba kompilują !! Scratch, scratch
Jak wspominali inni, 5 jest ikoną int
i null
nie można jej niejawnie przekonwertować na int
.
Oto inne sposoby obejścia tego problemu:
int? num = true ? 5 : default(int?);
int? num = true ? 5 : new int?();
int? num = true ? 5 : null as int?;
int? num = true ? 5 : (int?)null;
int? num = true ? (int?)5 : null;
int? num = true ? 5 as int? : null;
int? num = true ? new int?(5) : null;
Ponadto, gdziekolwiek zobaczysz int?
, możesz również użyć Nullable<int>
.
W C# 9
tym jest teraz dozwolone blogowanie
Wpisano cel ?? i ?
Czasami warunkowe? i?: wyrażenia nie mają oczywistego typu współdzielonego między gałęziami. Takie przypadki zawodzą dzisiaj, ale C # 9.0 na to pozwoli, jeśli istnieje typ docelowy, na który obie gałęzie konwertują:
Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type
Albo twój przykład:
// Allowed in C# 9.
int? number = true ? 5 : null;