Frage

public class Foo : IFooBarable {...}
public class Bar : IFooBarable {...}

Warum wird dann nicht die Kompilierung ...

int a = 1;
IFooBarable ting = a == 1 ? new Foo() : new Bar();

Das wird aber ...

IFooBarable ting = a == 1 ? new Foo() : new Foo();
IFooBarable ting = a == 1 ? new Bar() : new Bar();
War es hilfreich?

Lösung

Der Compiler versucht zunächst den rechten Ausdruck zu bewerten:

? new Foo() : new Bar();

Es gibt keine implizite Konvertierung zwischen diesen beiden daher der Fehlermeldung. Sie können dies tun:

IFooBarable ting = a == 1 ? (IFooBarable)(new Foo()) : (IFooBarable)(new Bar());

Andere Tipps

Dies ist in Abschnitt 7.13 der Sprache C # spec abgedeckt. Im Wesentlichen, was dieses Szenario tötet ist, dass es eine implizite Konvertierung zwischen den Typen der 2 Werte für die ternären Operanden sein muss. Diese Umwandlung wird im abscence des Typs der Variablen betrachtet.

Also entweder Foo muss kehrt Bar oder umge konvertierbar sein. Weder ist so ein Übersetzungsfehler auftritt.

Diese 2 Arbeit obwohl, weil sie nur betrachten 1-Typ (entweder Foo oder Bar). Weil sie vom gleichen Typ Bestimmung der Art des Ausdrucks sind ist einfach und es funktioniert gut.

Sie einfach ein bisschen auf die richtigen Antworten hinzuzufügen hier gepostet: Es gibt zwei Design-Richtlinien, dass Blei zu dieser Spezifikation

.

Das ist zunächst, dass wir Grund von „innen nach außen“. Wenn Sie sagen,

double x = 2 + y;

wir erste Arbeit aus der Art von x, dann ist die Art von 2, dann die Art von y, dann ist die Art von (2 + y) und schließlich arbeiten wir heraus, ob x und (2 + y) haben kompatibel Typen. Aber wir den Typ von x NICHT bei der Entscheidung verwenden, was die Art der 2, y oder 2 + y ist.

Der Grund dafür ist eine gute Regel ist, weil oft die Art des „Empfängers“ ist genau das, was wir versuchen zu erarbeiten:

void M(Foo f) {}
void M(Bar b) {}
...
M(x ? y : z);

Was wir hier tun? Wir müssen den Typ des bedingten Ausdrucks, um herauszufinden Auflösung zu tun Überlastung, um festzustellen, ob es sich um Foo oder Bar wird. Deshalb können wir nicht Verwendung die Tatsache, dass es sich dabei, sagen wir, in unserer Analyse der Art des bedingten Ausdruck Foo gehen! Das ist ein Henne-Ei-Problem.

Die Ausnahme von dieser Regel ist, Lambda-Ausdrücke, die Sie ihre Art aus ihrem Kontext nehmen. Machen dieses Feature richtig funktioniert irrsinnig kompliziert war; siehe meine Blog-Serie auf Lambda-Ausdrücke vs anonyme Methoden, wenn Sie daran interessiert sind.

Das zweite Element ist, dass wir nie „magic up“ eine Art für Sie. Wenn ein paar Dinge aus der gegeben wir einen Typ ableiten, müssen wir eine Art immer ableiten, die tatsächlich direkt vor uns.

In Ihrem Beispiel geht die Analyse wie folgt aus:

  • Arbeit aus der Art der Folge
  • Arbeit aus der Art der alternativen
  • finden Sie die beste Art, die sowohl kompatibel mit der Folge, und die Alternative
  • stellen Sie sicher, dass es eine Umwandlung von dem Typ des bedingten Ausdrucks auf die Art der Sache, die den bedingten Ausdruck verwendet wird.

mit dem ersten Punkt Entsprechend, wissen wir nicht Grund von außen nach innen ; Wir verwenden nicht die Tatsache, dass wir die Art der Variablen wir gehen zu kennen, um die Art des Ausdrucks zu erarbeiten. Aber das Interessante ist nun, dass, wenn Sie haben

b ? new Cat() : new Dog()

wir sagen, „der Typ des bedingten Ausdrucks ist die beste Art in der Menge {Katze, Hund}“. Wir sagen nicht, „der Typ des bedingten Ausdrucks ist die beste Art kompatibel mit Katze und Hund“. Das wäre Säugetier, aber wir tun das nicht. Stattdessen sagen wir „das Ergebnis hat etwas, das wir tatsächlich Säge sein“, und von diesen beiden Entscheidungen, weder ist der klare Sieger. Wenn Sie die

b ? (Animal) (new Cat()) : new Dog()

, dann haben wir die Wahl zwischen Tier und Hund, und Tier ist der klare Sieger.

Jetzt beachten Sie, dass wir eigentlich nicht korrekt den C # spec implementieren, wenn diese Art Analyse zu tun! Für Einzelheiten des Fehlers finden Sie in meinem

Da der Typ des bedingten Ausdrucks immer von seinen beiden Teilen abgeleitet wird, nicht von den Variablen, auf die das Ergebnis angewandt werden. Diese Folgerung funktioniert nur, wenn die Typen gleich ist oder eine Referenz kompatibel zu den andere. In diesem Fall ist keine der beiden Arten Referenz kompatibel zu den anderen.

scroll top