Der Typ des bedingten Ausdrucks kann nicht bestimmt werden, da keine implizite Konvertierung zwischen 'int' und <null> erfolgt

Antworten:

336

Die Spezifikation (§7.14) besagt, dass es für den bedingten Ausdruck b ? x : ydrei Möglichkeiten gibt, entweder xund ybeide haben einen Typ und bestimmte gute Bedingungen sind erfüllt, nur eine von xund yhat einen Typ und bestimmte gute Bedingungen sind erfüllt, oder ein Fehler bei der Kompilierung tritt ein. Hier bedeutet "bestimmte gute Bedingungen", dass bestimmte Konvertierungen möglich sind, auf die wir im Folgenden näher eingehen werden.

Wenden wir uns nun dem deutschen Teil der Spezifikation zu:

Wenn nur einer von xund yeinen Typ hat und beide xund yimplizit in diesen Typ konvertierbar sind, dann ist dies der Typ des bedingten Ausdrucks.

Das Problem hier ist, dass in

int? number = true ? 5 : null;

Nur eines der bedingten Ergebnisse hat einen Typ. Hier xist eine intwörtliche, und yist nulldie sich nicht einen Typ haben und nullist nicht implizit konvertierbar zu einem int1 . Daher werden "bestimmte gute Bedingungen" nicht erfüllt, und es tritt ein Fehler bei der Kompilierung auf.

Es gibt zwei Möglichkeiten, dies zu umgehen:

int? number = true ? (int?)5 : null;

Hier sind wir noch in dem Fall, dass nur einer von xund yeinen Typ hat. Beachten Sie, dassnull nach wie vor nicht über eine Art noch der Compiler habe kein Problem mit diesem , weil (int?)5und nullbeide implizit konvertierbar int?(§ 6.1.4 und §6.1.5).

Der andere Weg ist offensichtlich:

int? number = true ? 5 : (int?)null;

aber jetzt müssen wir a lesen andere Klausel in der Spezifikation zu verstehen, warum dies in Ordnung ist:

Wenn xhat Typ Xundy hat Typ Ydann

  • Wenn eine implizite Konvertierung (§6.1) von Xbis Y, aber nicht von Ybis bestehtX , Yist dies der Typ des bedingten Ausdrucks.

  • Wenn eine implizite Konvertierung (§6.1) von Ybis X, aber nicht von Xbis bestehtY , Xist dies der Typ des bedingten Ausdrucks.

  • Andernfalls kann kein Ausdruckstyp ermittelt werden, und es tritt ein Fehler bei der Kompilierung auf.

Hier xist vom Typ intund yist vom Typ int?. Es gibt keine implizite Konvertierung von int?nach int, aber es gibt eine implizite Konvertierung von intnach, int?so dass der Typ des Ausdrucks ist int?.

1 : Beachten Sie ferner, dass der Typ der linken Seite bei der Bestimmung des Typs des bedingten Ausdrucks ignoriert wird, was hier häufig zu Verwirrung führt.

Jason
quelle
4
Gutes Zitat der Spezifikation, um zu veranschaulichen, warum dies passiert - +1!
JerKimball
7
Eine andere Option ist new int?()anstelle von (int?)null.
Guvante
1
Dies ist auch der Fall, wenn Sie einen nullbaren Datenbankfeldtyp haben, z. B. eine nullbare DateTime, und Sie versuchen, Daten zu übertragen DateTime, wenn dies erforderlich ist(DateTime?)
Mike Upjohn
73

null hat keinen identifizierbaren Typ - es muss nur ein wenig gestoßen werden, um glücklich zu werden:

int? number = true ? 5 : (int?)null;
Marc Gravell
quelle
2
Oder Sie können tunint? number = true ? 5 : null as int?;
Brad M
Schöne Antwort, die den Punkt trifft. Schöne verwandte Lektüre: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Benjamin Gruenbaum
Das Problem ist nicht, dass nulles keinen identifizierbaren Typ gibt. Das Problem ist, dass es keine implizite Konvertierung von nullnach gibt int. Details hier .
Jason
das interessante ist das int? number = true ? 5 : (int?)null;und int? number = true ? (int?)5 : null;beide kompilieren !! Scratch, Scratch
Davidhq
2
Ich beschreibe in meiner Antwort genau, warum dies passiert .
Jason
4

Wie andere bereits erwähnt haben, ist die 5 eine intund nullkann nicht implizit in konvertiert werdenint .

Hier sind andere Möglichkeiten, um das Problem zu umgehen:

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;

Auch überall, wo Sie sehen int?, können Sie auch verwenden Nullable<int>.

Andrew
quelle
1

In C# 9diesem Blog ist jetzt erlaubt

Ziel getippt? und ?

Manchmal bedingt ?? und ?: Ausdrücke haben keinen offensichtlichen gemeinsamen Typ zwischen den Zweigen. Solche Fälle schlagen heute fehl, aber C # 9.0 lässt sie zu, wenn es einen Zieltyp gibt, in den beide Zweige konvertieren:

Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type

Oder dein Beispiel:

// Allowed in C# 9.
int? number = true ? 5 : null;
WBuck
quelle