Nie można określić typu wyrażenia warunkowego, ponieważ nie ma niejawnej konwersji między „int” i <null>

Odpowiedzi:

340

Spec (§7.14) mówi, że dla wyrażenia warunkowego b ? x : y, istnieją trzy możliwości, albo xi yobie mają typ i pewne warunki dobre są spełnione, tylko jeden xi yma 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 xi yma typ, a oba xi ysą 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 xjest intdosłowne, i yto null, które ma nie mieć typ i nullnie jest niejawnie zamienny do int1 . 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 xi yma typ. Należy zauważyć, że null nadal nie ma typ jeszcze kompilator nie będzie miał żadnego problemu z tego powodu (int?)5i nullto 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 xma typ Xi yma typ Yto

  • Jeśli niejawna konwersja (§6.1) istnieje od Xdo Y, ale nie od Ydo X, to Yjest to typ wyrażenia warunkowego.

  • Jeśli niejawna konwersja (§6.1) istnieje od Ydo X, ale nie od Xdo Y, to Xjest 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 xjest typu inti yjest typu int?. Nie ma niejawna konwersja od int?celu int, ale istnieje niejawna konwersja z intdo 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ń.

Jason
źródło
4
Dobre cytowanie specyfikacji, aby zilustrować, dlaczego tak się dzieje - +1!
JerKimball
7
Inną opcją jest new int?()na miejscu (int?)null.
Guvante
1
Dzieje się tak również w przypadku, gdy masz typ pola bazy danych dopuszczający wartość null, na przykład DateTime dopuszczający wartość null, i próbujesz rzutować dane do DateTime, gdy jest to wymagane(DateTime?)
Mike Upjohn
73

null nie ma żadnego rozpoznawalnego typu - wystarczy trochę popchnąć, aby był szczęśliwy:

int? number = true ? 5 : (int?)null;
Marc Gravell
źródło
2
Lub możesz to zrobićint? number = true ? 5 : null as int?;
Brad M
Niezła odpowiedź na koniec. Przyjemna lektura powiązana: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Benjamin Gruenbaum
Problem nie polega na tym, nullże nie ma identyfikowalnego typu. Problem polega na tym, że nie ma niejawnej konwersji z nullna int. Szczegóły tutaj .
jason
interesującą rzeczą jest to, że int? number = true ? 5 : (int?)null;i int? number = true ? (int?)5 : null;oba kompilują !! Scratch, scratch
davidhq
2
I pokryć dokładnie dlaczego tak się dzieje w mojej odpowiedzi .
jason
4

Jak wspominali inni, 5 jest ikoną inti nullnie 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>.

Andrzej
źródło
1

W C# 9tym 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;
WBuck
źródło