2015-02-19 10 views
7

Ich würde gerne wissen, warum der erste Anruf an nicht funktioniert und der zweite tut. Scheint dumm, wenn ich bedenke, dass ich einen Typ object in beide Richtungen übergebe, und die Übergabe in einem anonymen Typ an Foo(object) funktioniert gut. Warum würde ref, etwas, das mit Speicherstandort zu tun hat, die Aufrufe von Bar() beeinflussen?Kann ich ein anonymes Objekt in eine Methode übergeben, die einen Referenzparameter vom Typ Objekt erwartet?

Betrachten Sie das folgende Snippet:

static void Foo(object obj) 
{ } 

static void Bar(ref object obj) 
{ } 

static void Main() 
{ 
    // Compiles 
    var a = new { }; 
    Foo(a); 

    // Does not compile 
    var b = new { }; 
    Bar(ref b); 

    // Compiles 
    object c = new { }; 
    Bar(ref c); 
} 

ich in den Antworten siehe unten Vorschläge, wie Sie den Code der Kompilierung zu machen, aber das ist nicht das, was ich bin nach. Ich würde gerne wissen, warum die Erstellung eines ref Parameter verhindert Kompilierung bei der Übergabe in einem anonymen Typ an Foo() hat gut funktioniert.

Antwort

7

Der Hauptgrund ist ein wenig versteckt: Dies passiert, weil Ihr übergebenes Argument genau gleichen Typ wie der im Parameter definierte Typ sein muss.

Dies ist (? Zweideutig) angegeben in der Spezifikation Abschnitt $ 10.6.1.2:

Wenn ein formaler Parameter ein Referenzparameter ist, wird das entsprechende Argument in einem Methodenaufruf muss das Schlüsselwort ref bestehen gefolgt durch eine Variablen-Referenz (§5.3.3) des gleichen Typs wie der formale Parameter.

Aus genau diesem Grund funktioniert die Übergabe einer Unterklasse an eine Methode, die einen Referenzparameter verwendet, nicht. Dies wird in der Antwort von Jeff Mercado beschrieben.

In Ihrem ersten Beispiel, das Sie nicht ref so Polymorphismus Werke verwenden (ein anonymer Typ ist ein Subtyp der object) und im letzten Beispiel können Sie es als object erklären, was bedeutet, dass Sie genau die gleiche Art als Referenzparameter verwenden.

5

Warum sollte es? Die Variable b ist nicht als object deklariert, wie von der Methode erwartet.

Betrachten Sie dieses Beispiel:

string s; 
GetValue(ref s); // no... 

void GetValue(ref object x) 
{ 
    x = 123; 
} 
+0

danke. Aber anonym an "Foo (object)" zu kommen, war kein Problem. Warum verhindert die Angabe eines 'ref' die Kompilierung? – Didaxis

+0

Ich könnte die Spezifikation, aber das Beispiel sollte es klar machen, warum es _should_ scheitern sollte. –

+0

Danke, Ihre Antwort ist gleich gut, aber ich schätze die Spezifikationsangabe unten. Danke jedenfalls, ich upvoted das :) – Didaxis

-1

Typ-Inferenz smart ist, aber es ist nicht in der Lage, Ihre Meinung zu lesen. So einfach var b = new { }; zu deklarieren ist einfach nicht genug Informationen, um den Compiler zu verstehen, dass Sie etwas wollen, das als Objekt ref-übergeben werden kann.

var b = new Object(); 
Bar (ref b); 

wird natürlich funktionieren.

+0

Dies ist eigentlich falsche Antwort - wie andere Antworten darauf hinweisen, dass der gleiche Fehler für jede Art Mismatch passieren wird - es gibt keine Art Rückschluss hier beteiligt. –

+0

@AlexeiLevenkov - in dem Moment, in dem Sie 'var' verwenden, kommt die Moment-Typ-Inferenz ins Spiel - und dies ** erzeugt ** den Typ-Mismatch. Und in dem Moment, in dem Sie 'var' genügend Informationen geben, dass es den richtigen Typ erhält, wird der Typenkonflikt (und der resultierende Kompilierzeitfehler) verschwinden. –

+0

'var' verwendet den genau richtigen Typ hinter den Kulissen, nichts wird falsch abgeleitet. Indem Sie den anonymen Typ als "Objekt" definieren, wird er einfach auf eine allgemeinere Spezifikation umgestellt, die der Definition der Methode entspricht. Wenn Sie stattdessen ein Objekt erstellen, wird die Frage nicht beantwortet, da Sie jetzt keinen anonymen Typ verwenden. –

0

durch die nicht zulassen, die Funktion mit ref zusammen mit Parameter-Typ, der Compiler ist eigentlich verhindert, einen Kompromiss mit Typ Sicherheit. Dasselbe geschieht in dem folgenden Szenario auch

private static void MyMethod(out object MyPara) 
    { 
     MyPara = new String('x', 10); 
    } 

    MyClass obj = new MyClass(); 
    MyMethod(out obj); //compile time error 

Compiler wird den Speicherplatz von obj sicher tatsächlich zu halten, indem sie keine dieses Szenario zu kompilieren.Wenn dies erlaubt worden wäre, könnte die Sicherheit der Anwendung leicht beeinträchtigt werden