2015-02-19 41 views
7

Mi piacerebbe sapere perché la prima chiamata a Bar(ref object) non funziona e la seconda. Sembra sciocco considerando che sto passando in un tipo e e passando in un tipo anonimo a Foo(object) funziona bene. Perché ref, qualcosa che ha a che fare con la posizione della memoria influenza le chiamate a Bar()?Posso passare un oggetto anonimo in un metodo che si aspetta un parametro di riferimento di tipo oggetto?

Si consideri il seguente frammento di codice:

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); 
} 

vedo nelle risposte qui sotto suggerimenti su come rendere il codice di compilazione, ma non è quello che sto cercando. Mi piacerebbe sapere in modo specifico perché renderlo un parametro ref impedisce la compilazione quando il passaggio di un tipo anonimo a Foo() ha funzionato correttamente.

risposta

7

Il motivo principale è un po 'nascosto: questo accade perché il vostro passato in argomento deve essere l'esatto stesso tipo come tipo definito nel parametro.

Questo è (? Ambiguo) ha dichiarato nella sezione specifica di $ 10.6.1.2:

Quando un parametro formale è un parametro di riferimento, l'argomento corrispondente in una chiamata di metodo deve consistere la parola chiave ref seguita tramite un riferimento variabile (§5.3.3) dello stesso tipo del parametro formale.

Per questo stesso motivo, passando una sottoclasse di un metodo che utilizza un parametro di riferimento non funziona. Questo è descritto nella risposta di Jeff Mercado.

Nel vostro primo esempio non si utilizza ref opere così polimorfismo (un tipo anonimo è un sottotipo di object) e nell'ultimo esempio si dichiara come object che significa che si utilizza lo stesso tipo esatto come parametro di riferimento.

5

Perché dovrebbe? La variabile b non è dichiarata come object come previsto dal metodo.

Considerate questo esempio:

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

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

grazie. Ma passare in anonimo a 'Foo (oggetto)' non era un problema. Perché quando si effettua il parametro a 'ref' si impedisce la compilazione? – Didaxis

+0

Potrei localizzare le specifiche ma l'esempio dovrebbe chiarire perfettamente il motivo per cui _should_ fallirebbe. –

+0

Grazie, la tua risposta è ugualmente buona, ma apprezzo la citazione delle specifiche qui sotto. Grazie comunque, ho svuotato questo :) – Didaxis

-1

tipo inferenza è intelligente, ma è in grado di leggere la tua mente. Quindi dichiarare semplicemente var b = new { }; non è abbastanza informazioni per far capire al compilatore, che vuoi qualcosa, che può essere passato come oggetto.

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

funzionerà naturalmente.

+0

Questa è in realtà una risposta errata - come altre risposte sottolineano che lo stesso errore si verificherà per qualsiasi tipo di mancata corrispondenza: non vi è alcun tipo di inferenza coinvolta qui. –

+0

@AlexeiLevenkov - nel momento in cui si usa 'var', l'inferenza del tipo di momento entra in gioco - e questo ** crea ** la mancata corrispondenza del tipo. E nel momento in cui date abbastanza informazioni a 'var', che ottiene il tipo corretto, la mancata corrispondenza di tipo (e l'errore di compilazione risultante) scomparirà. –

+0

'var' usa esattamente il tipo giusto dietro le quinte, nulla viene dedotto erroneamente. Definendo il tipo anonimo come un 'oggetto' lo si semplifica semplicemente una specifica più generale che si adatta alla definizione del metodo. La creazione come oggetto invece non risponde alla domanda perché ora non usi un tipo anonimo. –

0

non consentendo la funzione con ref insieme al tipo di parametro, il compilatore in realtà impedisce di compromettere la sicurezza del tipo. Lo stesso avviene nel seguente scenario così

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

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

compilatore è effettivamente mantenendo la locazione di memoria sicura obj non permettendo questo scenario per compilare.Se ciò fosse stato permesso, la sicurezza dell'applicazione può essere facilmente compromessa