2014-01-29 4 views
9

Ich fragte this question. Dieser Code lässt sich nicht kompilieren („Kann nicht konvertieren Generic<T>-T), weil der Grund here erklärt (auch wenn ich einen InvalidCastException zur Laufzeit erwarten würden statt ein Fehler bei der Kompilierung).Unerwartete Verhalten von "as" -Operator, es unterscheidet sich von Normalform

class NonGeneric 
{ 
} 

class Generic<T> : NonGeneric 
    where T : NonGeneric 
{ 
    T DoSomething() 
    { 
     return (T)this; // ** Cannot convert... 
    } 
} 

akzeptierte Lösung gab diese Abhilfe:

T DoSomething() 
{ 
    return this as T; 
} 

Meine Frage ist: warum? as Operator sollte exakt gleich wie Operator zu sein:

Der as-Operator ist wie ein Cast-Vorgang. Wenn die Konvertierung jedoch nicht möglich ist, wird null zurückgegeben, anstatt eine Ausnahme auszulösen.

Wenn this as T zu this is T? (T)this: (T)null gleichwertig sein sollte, warum dann as T Werke und (T)this nicht einmal kompilieren? AFAIK Guss konnte in einer Vielzahl von Situationen als as verwendet werden:

Beachten Sie, dass die als Operator führt nur Referenz Conversions, Nullable-Conversions und Boxen Konvertierungen. Der as-Operator kann keine anderen Konvertierungen ausführen, z. B. benutzerdefinierte Konvertierungen, die stattdessen mithilfe von Cast-Ausdrücken durchgeführt werden sollten.

Dann warum? Ist es eine dokumentierte Funktion von as Operator? Ist es eine Compiler-/Sprachbeschränkung mit generischen Typen? Beachten Sie, dass dieser Code kompiliert fein:

return (T)((object)this); 

Ist dies, weil Compiler nicht sicher sein kann, wenn T ist dynamic (auch wenn es eine where Einschränkung ist), dann wird es immer einen solchen Code generieren?

+0

Der Kompilierungsfehler besagt, dass Sie "NonGeneric " erben. Ist der Compiler verwirrt oder ist das Codebeispiel ungenau? –

+0

Gibt die 'DoSomething()' Funktion ein 'T' Objekt oder' null' zurück? –

+0

@KeithPayne Entschuldigung, falsche Fehlermeldung. behoben –

Antwort

5

Es heißt in der C# Language Specification (Hervorhebung von mir),

Wenn der Kompilierung-Typ von E nicht dynamisch ist, erzeugt die Operation E als T das gleiche Ergebnis wie E T ? (T) (E): (T) Null mit der Ausnahme, dass E nur einmal ausgewertet wird. Es kann erwartet werden, dass der Compiler E optimiert, um höchstens eine dynamische Typprüfung durchzuführen, im Gegensatz zu den zwei dynamischen Typprüfungen, die durch die obige Erweiterung impliziert sind.

Wenn der Kompilierung-Typ von E dynamic ist, im Gegensatz zu dem Cast-Operator der as Betreiber nicht dynamisch gebunden ist (§7.2.2). Deshalb ist die Expansion in diesem Fall: E is T ? (T)(object)(E) : (T)null

Dies scheint der Grund zu sein, warum die Zusammenstellung mit as Erfolg hat oder wenn this auf ein Objekt zuerst gegossen. Weiterhin

In einem Betrieb der Form E as T muss E ein Ausdruck sein und T muß ein Referenztyp, ein Typ-Parameter bekannt sein, um einen Referenztyp, oder ein NULL festlegbaren Typ sein. Darüber hinaus muss mindestens einer der folgenden Werte wahr sein oder andernfalls tritt ein Fehler bei der Kompilierung auf:

• Eine Identität (§6.1.1), implizite Nullwerte (§6.1.4), implizite Verweise (§6.1. 6), Boxen (§6.1.7), explizite Nullwert (§6.2.3), explizite Referenz (§6.2.4) oder Unboxing (§6.2.5) Konvertierung existiert von E zu T.

Der Typ E oder T ist ein offener Typ.

E ist die null wörtlich zu nehmen.

Welches ist der aktuelle Fall mit Ihrer generischen Klasse.

+0

In meinem Fall ist es nicht dynamisch, aber ich nehme an, dass der Compiler sich deswegen nicht beschwert! Vielen Dank! –

+1

Jackpot! Ich bin mir ziemlich sicher, dass die MSDN-Dokumentation dieses kleine Detail nicht enthält. – dcastro

+2

Warum der Downvote? – rae1

5

Nach msdn: -

Der als Operator wie ein Guss Betrieb ist. Wenn die Konvertierung jedoch nicht möglich ist, wird null zurückgegeben, anstatt eine Ausnahme auszulösen. Der Code entspricht dem folgenden Ausdruck, außer dass die Ausdrucksvariable nur einmal ausgewertet wird.

expression is type ? (type)expression : (type)null 

Ein weiterer Unterschied ist, dass: -

Beachten Sie, dass die als Operator nur Referenz Conversions, Nullable-Conversions und Boxen Konvertierungen durchführt. Der as-Operator kann keine anderen Konvertierungen ausführen, z. B. benutzerdefinierte Konvertierungen, die stattdessen mithilfe von Cast-Ausdrücken durchgeführt werden sollten.

+0

-1 Nein, das ist, was ich erwarten würde, aber es ist ** nicht ** äquivalent, weil (Typ) Ausdruck fehlschlägt, sogar zu kompilieren. Das ist, warum meine Frage ... –

+0

Es kompiliert nicht, weil der Compiler weiß, dass der Cast (zur Kompilierungszeit) fehlschlägt, aber im Fall von 'as' hat es die Option, null zurückzugeben (wenn der Cast fehlschlägt) kompiliert es erfolgreich. –

+0

** Nein **, Cast ** kann ** zur Laufzeit fehlschlagen. Es sollte es nicht ablehnen (siehe Bearbeiten für einen anderen Fall). Zumindest sollte es sowohl Cast als auch "as" -Operator ablehnen ... –

-5

‚als‘ Operator in C# führt diese Aktionen durch: -

  1. Es gibt null zurück, wenn bestimmte Variable nicht von bestimmtem Typ eines seines Basistypen ist. Es wird keine Ausnahme ausgelöst
  2. Kann nur mit Referenztypvariablen angewendet werden.
  3. ‚als‘ keine Konvertierung macht (implizit/explizit)

‚als‘ Operator ist etwas schneller als jeder Gießen (auch in Fällen, in denen es keine ungültige Würfe sind die würde erheblich geringere Leistung Gussteil der aufgrund Ausnahmen).

Verwandte Themen