passing pass parameter funciona ejemplos como c# ref

pass - ref out c# ejemplos



¿Cómo funciona la palabra clave ref(en términos de memoria) (4)

Pasando una variable local como referencia

En el nivel bajo, la variable int local referenciada se colocará en la pila (la mayoría de los enteros de tiempo se almacenarán en registros), y se pasará un puntero a la pila a la función invocada (el puntero en sí es más probable que se pase) en un registro). Considere el siguiente ejemplo:

var i = 7; Console.WriteLine(i); inc(ref i); Console.WriteLine(i);

Esto será JIT-et a algo como esto (la arquitectura de destino es x86):

17: var i = 7; # allocate space on the stack for args and i 00482E3B sub esp,8 # initialize i to 0 00482E3E xor eax,eax 00482E40 mov dword ptr [ebp-8],eax # args saved to stack (could be optimised out) 00482E43 mov dword ptr [ebp-4],ecx 00482E46 cmp dword ptr ds:[3ACAECh],0 00482E4D je 00482E54 00482E4F call 7399CB2D # i = 7 00482E54 mov dword ptr [ebp-8],7 18: Console.WriteLine(i); # load the value of i into ecx, and call cw 00482E5B mov ecx,dword ptr [ebp-8] 00482E5E call 72E729DC 19: inc(ref i); # load the address of i into ecx, and call inc 00482E63 lea ecx,[ebp-8] 00482E66 call dword ptr ds:[4920860h] 20: Console.WriteLine(i); # load the value of i into ecx, and call cw 00482E6C mov ecx,dword ptr [ebp-8] 00482E6F call 72E729DC 21: } 00482E74 nop 00482E75 mov esp,ebp 00482E77 pop ebp 00482E78 ret

Pasar un elemento de matriz o un miembro de objeto como referencia

Casi lo mismo sucede aquí, se obtiene la dirección del campo o elemento, y el puntero se pasa a la función:

var i = new[]{7}; Console.WriteLine(i[0]); inc(ref i[0]); Console.WriteLine(i[0]);

Compila (sin la parte aburrida):

18: Console.WriteLine(i[0]); 00C82E91 mov eax,dword ptr [ebp-8] 00C82E94 cmp dword ptr [eax+4],0 00C82E98 ja 00C82E9F 00C82E9A call 7399BDC2 00C82E9F mov ecx,dword ptr [eax+8] 00C82EA2 call 72E729DC 19: inc(ref i[0]); # loading the reference of the array to eax 00C82EA7 mov eax,dword ptr [ebp-8] # array boundary check is inlined 00C82EAA cmp dword ptr [eax+4],0 00C82EAE ja 00C82EB5 # this would throw an OutOfBoundsException, but skipped by ja 00C82EB0 call 7399BDC2 # load the address of the element in ecx, and call inc 00C82EB5 lea ecx,[eax+8] 00C82EB8 call dword ptr ds:[4F80860h]

Tenga en cuenta que la matriz no tiene que estar anclada en este caso , ya que el marco de trabajo sabe que la dirección en ecx está apuntando un elemento dentro de la matriz, por lo que si se produce una compresión del montón entre lea y call o dentro de la función inc, puede reajustar el valor de ecx directamente.

Puede investigar el ensamblaje JIT-ed usted mismo utilizando el depurador de Visual Studio abriendo la ventana Desensamblar ( Depurar / Windows / Desensamblar )

C # tiene una palabra clave ref . Usando ref puedes pasar un int a un método por referencia. ¿Qué sucede en el marco de la pila cuando llama a un método que acepta un int por referencia?

public void SampleMethod(ref int i) { }


Aquí hay un ejemplo simple en código C #:

void Main() { int i = 1; inc(ref i); Console.WriteLine(i); } public void inc(ref int i) { i++; }

Aquí está el código IL generado

IL_0000: nop IL_0001: ldc.i4.1 IL_0002: stloc.0 // i IL_0003: ldarg.0 IL_0004: ldloca.s 00 // i IL_0006: call inc IL_000B: nop IL_000C: ldloc.0 // i IL_000D: call System.Console.WriteLine IL_0012: nop IL_0013: ret inc: IL_0000: nop IL_0001: ldarg.1 IL_0002: dup IL_0003: ldind.i4 IL_0004: ldc.i4.1 IL_0005: add IL_0006: stind.i4 IL_0007: ret

Tenga en cuenta que con este caso simple realmente hay solo una diferencia: ldloca.s 00 o ldloc.0. Cargar dirección local o de carga (de offset 00)

Esa es la diferencia en el nivel más simple (que es lo que pidió en su comentario): si carga el valor de la variable o si carga la dirección de la variable. La cosa puede complicarse rápidamente: si la función que está llamando no es local, si la variable que está pasando no es local, etc., etc. Pero a un nivel básico, esta es la diferencia.

Usé el linqpad para hacer mi desmontaje rápido, lo recomiendo. http://www.linqpad.net/


La dirección de la variable o campo local. En la IL, la instrucción ldloca.s se usa para una variable local.

Carga la dirección de la variable local en un índice específico en la pila de evaluación

La instrucción stind se utiliza para almacenar el valor de nuevo en la variable

Almacene el valor del tipo (...) en la memoria en la dirección

La dirección es de 32/64 bits, dependiendo de la arquitectura de destino.


Pasará la variable local por referencia en lugar de enviar una nueva copia para ella