Qual è la differenza tra ref e out in runtime?

13

C # fornisce la ref e la out keyword per rendere gli argomenti da passare per riferimento. La semantica dei due è molto simile. L'unica differenza è nell'inizializzazione della variabile flaged:

  • ref richiede che la variabile venga inizializzata prima di passarla alla funzione, out non lo fa.
  • out richiede che la variabile venga inizializzata all'interno della funzione, ref no.

Anche i casi d'uso di queste due parole chiave sono quasi gli stessi, e il loro utilizzo troppo frequente è considerato un odore di codice (sebbene ci siano casi d'uso validi come TryParse e TryGetValue patterns).

Per questo qualcuno potrebbe spiegare, perché ci sono due strumenti molto simili in C # per casi d'uso così stretti?

Inoltre, su MSDN , si afferma che hanno un comportamento di runtime differente:

Although the ref and out keywords cause different run-time behavior, they are not considered part of the method signature at compile time.

In che modo il loro comportamento in fase di esecuzione è diverso?

Conclusione

Entrambe le risposte sembrano corrette, grazie a entrambi. Ho accettato jmoreno perché è più esplicito.

    
posta Gábor Angyal 10.02.2015 - 11:04
fonte

3 risposte

9

L'articolo MSDN è leggermente errato. Invece di "causare un comportamento diverso" dovrebbe essere "richiede un comportamento diverso".

In particolare, il compilatore applica diversi requisiti per le due parole chiave, anche se lo stesso mecanism (IL) viene utilizzato per abilitare il comportamento.

    
risposta data 10.02.2015 - 16:34
fonte
4

Ecco un interessante articolo sull'argomento che potrebbe rispondere alla tua domanda:

link

punto di interesse:

"La differenza tra ref e out non è nel Common Language Runtime, ma è nel linguaggio C # stesso."

Aggiornamento:

lo sviluppatore senior del mio lavoro ha appena confermato la risposta di @ jmoreno, quindi assicurati di averlo letto!

    
risposta data 10.02.2015 - 14:08
fonte
1

Runtime ? Assolutamente nessuno. Non puoi sovraccaricare un metodo con gli stessi parametri che differiscono solo dalla parola chiave ref or out.

Prova a compilarlo e riceverai un errore di compilazione "Metodo con la stessa firma già dichiarato":

    private class MyClass
    {
        private void DoSomething(out int param)
        {
        }
        private void DoSomething(ref int param)
        {
        }
    }

Per rispondere a questa domanda:   "... perché ci sono due strumenti molto simili in C # per casi d'uso così stretti?"

Da una leggibilità del codice e dal punto di vista dell'API c'è un'enorme differenza. Come consumatore dell'API, so che quando viene utilizzato "out" l'API non dipende dal parametro out. Come sviluppatore dell'API preferisco il "fuori" e uso "ref" solo quando assolutamente (RARAMENTE!) Necessario. Vedi questo riferimento per una grande discussione:

link

Informazioni di supporto: ho compilato il seguente metodo e l'ho disassemblato. Ho usato le parole chiave ref e out (in questo esempio), ma il codice assembly non è stato modificato tranne per un riferimento agli indirizzi, come mi sarei aspettato:

    private class MyClass
    {
        internal void DoSomething(out int param)
        {
            param = 0;
        }
    }

00000000 push ebp
00000001 mov ebp, esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp, 34h
00000009 xor eax, eax
0000000b mov dword ptr [ebp-10h], eax
0000000e mov dword ptr [ebp-1Ch], eax
00000011 mov dword ptr [ebp-3Ch], ecx
00000014 mov dword ptr [ebp-40h], edx
00000017 cmp dword ptr ds: [008B1710h], 0
0000001e je 00000025
00000020 chiama 6E6B601E
00000025 nop
                param = 0;
00000026 mov eax, dword ptr [ebp-40h]
00000029 xor edx, edx
0000002b mov dword ptr [eax], edx
            }
0000002d nop
0000002e lea esp, [ebp-0Ch]
00000031 pop ebx
00000032 pop esi
00000033 pop edi
00000034 pop ebp
00000035 ret

Sto leggendo correttamente l'assemblaggio?

    
risposta data 12.02.2015 - 02:20
fonte

Leggi altre domande sui tag