2010-02-07 5 views
53

Ich bin von diesem kleinen C# Marotte stapfte wenig:Bedingter Operator kann nicht implizit umwandeln?

Da Variablen:

Boolean aBoolValue; 
Byte aByteValue; 

Folgende compiliert:

if (aBoolValue) 
    aByteValue = 1; 
else 
    aByteValue = 0; 

aber das wird nicht:

aByteValue = aBoolValue ? 1 : 0; 

Fehler sagt: „Kann nicht implizit Typ konvertieren‚int‘auf‚byte‘.“

Und natürlich wird diese Ungeheuerlichkeit kompilieren:

aByteValue = aBoolValue ? (byte)1 : (byte)0; 

Was hier los?

EDIT:

VS2008 verwenden, C# 3.5

+0

mögliche Duplikate von [Nurable Typen und der ternäre Operator: warum ist \ '? 10: null \ 'verboten?] (Http://stackoverflow.com/questions/858080/nullable-types-and-the-ternary-operator-why-is-10-null-forbidden) – nawfal

Antwort

62

Dies ist eine ziemlich häufig gestellte Frage.

In C#, wir fast immer von innen nach außen Grund. Wenn Sie

x = y; 

sehen wir herausfinden, was die Art von x ist, was ist die Art von y, und ob die Art der y Zuordnung mit x kompatibel. Aber wir nutzen nicht die Tatsache, dass wir wissen, was der Typ von x ist, wenn wir den Typ von y ausarbeiten.

, dass, weil es könnte mehr sein als ein x:

void M(int x) { } 
void M(string x) { } 
... 
M(y); // y is assigned to either int x or string x depending on the type of y 

Wir Notwendigkeit der Lage sein, den Typ eines Ausdrucks arbeiten ohne zu wissen, was es zugewiesen wird.Typ Informationsflüsse aus eines Ausdrucks, nicht in ein Ausdruck.

Um den Typ des Bedingungsausdrucks zu ermitteln, berechnen wir den Typ der Konsequenz und die alternativen Ausdrücke, wählen den allgemeineren der beiden Typen aus, und dies wird zum Typ des Bedingungsausdrucks. In Ihrem Beispiel ist der Typ des Bedingungsausdrucks "int" und keine Konstante (es sei denn, der Bedingungsausdruck ist konstant wahr oder konstant falsch). Da es keine Konstante ist, können Sie es nicht Byte zuweisen; der Compiler begründet sich ausschließlich aus den Typen, nicht aus den Werten, wenn das Ergebnis keine Konstante ist.

Die Ausnahme von all diesen Regeln sind Lambda-Ausdrücke, wobei die Typinformation von dem Kontext in das Lambda fließt. Es war sehr schwierig, diese Logik richtig zu machen.

+2

Mein Kopf ist durchgebrannt . Danke, mein Herr, das ist ein Teil erleuchtend und zwei Teile frustrierend. Eines, weil es nicht so funktionieren kann, wie es scheinen würde, und zwei, weil es Sinn macht, dass es so nicht funktionieren kann. Also ... Konstanten ist es! – MPelletier

+0

Danke. Ich war auf der Suche nach einem Beitrag zu diesem Thema in Ihrem Blog, aber das ist noch besser. –

+0

@John: Ich spreche über diese Probleme ein wenig hier: http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx –

5

Ich kann nicht eine große Antwort für Sie, aber wenn Sie dies tun, in vielen Orten, könnten Sie erklären:

private static readonly Byte valueZero = (byte)0; 
private static readonly Byte valueOne = (byte)1; 

und nur diese Variablen. Sie könnten bei der Verwendung von const weg, wenn es um das Projekt lokal ist.

EDIT:readonly mit würde keinen Sinn machen - diese sind nicht immer ändern gemeint.

+0

Ich bin mir sicher, dass es war nur ein Tippfehler, aber Sie haben die gleiche Variable zweimal deklariert. –

+1

@Hamish: Ich verstehe was du meinst. Ich könnte const verwenden, aber es ist ein Workaround. Das verdient sicherlich nicht die Stimme, die Sie bekommen haben. – MPelletier

9

Ich verwende VS 2005, und ich nicht wiedergeben kann, für Bool & Boolean, aber nicht für echte

bool abool = true; 
Boolean aboolean = true; 
Byte by1 = (abool ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte' 
Byte by2 = (aboolean ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte' 
Byte by3 = (true ? 1 : 2);  //Warning: unreachable code ;) 

Die einfachste Abhilfe scheint diese

Byte by1 = (Byte)(aboolean ? 1 : 2); 

gegossen, so zu sein, ja, so scheint es, dass der ternäre Operator die Konstanten verursacht zu „reparieren“ ihre Typen wie ints und deaktivieren Sie die implizite Typumwandlung, die Sie sonst von Konstanten erhalten, die innerhalb des kleineren Typs passen.

+0

+1 für eine Besetzung weniger hässlich als meine :) – MPelletier

+1

Ihre Erklärung ergibt Sinn. Aber warum sollten die Konstanten in diesem Fall nicht behoben werden? Und doppelt neugierig auf Mendys Entdeckung. Jemand bei Microsoft sollte wissen, und möglicherweise mit stark argumentiert werden müssen ... – MPelletier

+0

Ich denke, Mendy entdeckte, dass, wenn Compiler trivial erkennen kann, dass es den ternären Operator vollständig optimieren kann, es der compiles-Code ist, der Byte by gleich ist 2 ', die die Fähigkeit zur impliziten Besetzung bewahrt. (Siehe meinen Kommentar zur Compiler-Warnung oben) –