2016-08-08 22 views
6

Ich habe drei Klassen (classA, classB und classC), die von einer Schnittstelle 'IFoo' erben; wenn verwenden dieseWie funktioniert null-collesescing-Operator

var fooItem = (request.classAitem ?? (request.classBitem as IFoo ?? request.classCitem)) 

oder

var fooItem = (request.classAitem ?? request.classBitem ?? request.classCitem as IFoo) 

es funktioniert gut, aber andere Kombinationen werden nicht einmal kompilieren:

var fooItem = (request.classAitem as IFoo ?? request.classBitem ?? request.classCitem) 

oder

var fooItem = (request.classAitem ?? request.classBitem ?? request.classCitem) as IFoo 

Es scheint mir, In einigen Fällen ist der Compiler implizit y hebt die Child-Klassen auf ihre IFoo-Schnittstelle auf, in einigen anderen Fällen jedoch nicht. Was denkt ihr?

+2

Was sind die Typen 'classAitem',' classBitem' und 'classCitem'? Bitte zeigen Sie die Definition von denen. Was ist ContactPoint? Implementiert das 'IFoo'? – poke

+0

kann nicht kompilieren, aber mit welchem ​​Fehler? – Doruk

+0

Bitte poste ein [mcve]. –

Antwort

5

In Ihre beiden Beispiele, die nicht arbeiten, weil ?? rechtsassoziativ ist, sind wir zunächst den Datentyp dieses Ausdrucks versucht, zu bestimmen:

request.classBitem ?? request.classCitem 

Der Datentyp nur das sein kann Datentyp eines seiner Eingänge, wenn die Datentypen unterschiedlich sind. Es gibt natürlich keine Conversions in beide Richtungen und Sie erhalten einen Compilerfehler. Beachten Sie, dass der Compiler nicht entscheiden, dass hier der Datentyp IFoo ist, nur weil beide Klassen zu ihrer Umsetzung geschehen (und wenn es so wäre, was passieren würde, wenn sie beide mehrere gemeinsame Schnittstellen implementiert?)

diese vergleichen zu Ihrer erste zwei Beispiele. Im ersten, betrachten wir zunächst diesen Ausdruck:

request.classBitem as IFoo ?? request.classCitem 

Die Art dieses Ausdrucks ist entweder IFoo oder was auch immer der Datentyp request.classCitem ist. Es gibt eine Konvertierung vom Typ von request.classCitem zu IFoo und so ist das natürlich ausgewählt und so ist der Datentyp des gesamten Ausdrucks IFoo. Dies wird dann verwendet, um den Typ des Gesamtausdrucks zu bestimmen (wiederum IFoo).

Der zweite Fall ist sehr ähnlich, da ?? rechts assoziative ist, müssen wir zunächst die Art der Bestimmung:

request.classBitem ?? request.classCitem as IFoo 

Und wieder haben wir die Wahl zwischen IFoo und unabhängig vom Datentyp von request.classBitem ist. Es gibt eine Umwandlung zu IFoo und so wird das gewählt.

Und beachten Sie, dass es bedeutet, dass die Klammern im ersten Beispiel überflüssig sind.

+0

Ich sehe Ihren Punkt: Es wertet den vollständigen Ausdruck beginnend von rechts, "var fooItem = (request.classAitem als ContactPoint ?? request.classBitem ?? request.classCitem) "wird nicht funktionieren, weil es als erstes evaluiert" request.classBitem ??request.classCitem "das ist unlösbar, weil, wie Sie sagten, Klasse B und KlasseC eine beliebige Anzahl von Schnittstellen teilen konnten. Große Antwort. – Zalomon

+1

@Zalomon - Ich war vorsichtig, das Wort" evaluate "zu vermeiden - weil es nicht * evaluate *' classBitem' oder 'classCitem' überhaupt, wenn' classAitem' nicht 'null' ist, sondern der * Datentyp * des gesamten Ausdrucks bestimmt werden muss, der die Datentypen aller möglichen Eingaben berücksichtigen muss. –