.Net way to understand the tape out, ref signature and the signature of the difference between the ordinary method

Today there was a new colleague asked me .Net in with OUT , ref method signature and the signature of the common methods What is the difference? I think we can explain some of the key areas from the following example.

A , REF / OUT Modifier Description

For use ref / out described in the modifier MSDN detailed description, the following address:

http://msdn.microsoft.com/en-us/library/t3c3bfhx(VS.80).aspx

 

Second, through the IL code is observed ref / out signature modification method ( a value type as an example )

1 , the sample code:

using  System;

namespace  ConsoleMain
{
    
class  Program
    {
        
static   void  Main()
        {
            Int32 p ;

            TestRef(
out  p);                              //

            
// TestRef(ref p)                         //
            
            TestRef(p);                         
//

            Console.ReadKey();
        }

        
static   void  TestRef(Int32 para)                  //
        {
            para 
=   1 ;
        }

        
static   void  TestRef( out  Int32 para)                 //
        {
            para 
=   2 ;
        }

        
/* static void TestRef(ref Int32 para)                //⑥
        {
            Para3 =  3;
        } 
*/
    }
}

2 , using the Reflector view the IL code is as follows:

(1) Main()

.method   private   hidebysig  static  void  Main()  cil   managed
{
    
.entrypoint
    
.maxstack   1
    
.locals   init  (
        [
0 int32  p)
    
L_0000:   ldloca.s  p
    
L_0002:   call   void  ConsoleMain.Program::TestRef( int32 &)
    
L_0007:   ldloc.0  
    
L_0008:   call   void  ConsoleMain.Program::TestRef( int32 )
    
L_000d:   call  valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    
L_0012: pop L_0013: right }    
    
   

(2) TestRef(ref Int32 para)

.method   private   hidebysig  static  void  TestRef( int32 & para)  cil   managed
{
    
.maxstack   8
    
L_0000:   ldarg.0  
    
L_0001:   ldc.i4.2  
    
L_0002:   stind.i4  
    
L_0003:   ret  
}

(3) TestRef (Int32 para)

.method   private   hidebysig  static  void  TestRef( int32  para)  cil   managed
{
    
.maxstack   8
    
L_0000:   ldc.i4.1  
    
L_0001:   starg.s  para
    
L_0003:   ret  
}

(4) TestRef(out Int32 para)

.method   private   hidebysig  static  void  TestRef([out]  int32 & para)  cil   managed
{
    
.maxstack   8
    
L_0000:   ldarg.0  
    
L_0001:   ldc.i4.2  
    
L_0002:   stind.i4  
    
L_0003:   ret  
}

. 3 , of IL code analysis

A method creates is called Evaluation Stack , local variables, method parameters, area and other storage area is created, reference may be made MSIL experience article.


 

1) Main()

.entrypoint

Current methods for the entry method;

.maxstack 1 ,

Created Evaluation Stack element is set to the maximum capacity of 1 ;

.locals init ([0] int32 p)

     pint32

L_0000: ldloca.s p

pEvaluation Stack


L_0002: call void ConsoleMain.Program ::TestRef (int32 &)

     callcall
    Call(this)
public   class  TestClass
{
    
private   void  InvokeTest()
    {
        Test(
1 );
    }

    
private   void  Test(Int32 i)
    {           
    }       
}   

InvokeTest方法的IL代码如下:
.method   private   hidebysig   instance   void  InvokeTest()  cil   managed
{
   
.maxstack   8
    
L_0000:   ldarg.0  
    
L_0001:   ldc.i4.1  
    
L_0002:   call   instance   void  ConsoleMain.TestClass::Test( int32 )
    
L_0007:   ret  
}

L_0000: ldarg.0TestTestEvaluation Stackarg0TestClassthisStaticarg0

     CallVrtual tableCallCallvirt

     MainEvaluation Stack&pTestRef(int32&)TestRef(int32&)MainEvaluation Stackref&

L_0007: ldloc.0

     Mainp

L_0008: call void ConsoleMain.Program::TestRef(int32)

     MainEvaluation StackpTestRef(int32)TestRef(int32)

L_000d: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()

     mscorlib.dllReadKey(valuetype)System.ConsoleKeyInfoMainEvaluation Stack

L_0012: pop  L_0013: ret,

     MainEvaluation StackMain

 

2)TestRef(ref Int32 para)

 L_0000: ldarg.0

    0Evaluation Stack

L_0001: ldc.i4.2

    int322Evaluation Stack

L_0002: stind.i4

    Evaluation Stack(valueaddress)valueaddress

L_0003: ret

 

3)TestRef(Int32 para)

L_0000:ldc.i4.1

执行完成后的堆栈变化情况



L_0001: starg.s para

执行完成后的堆栈变化情况



L_0003: ret

方法返回,相应的Evaluation Stack、局部变量区、方法参数区等存储区被释放。

 

4)TestRef(out Int32 para)

     从方法签名上看它只比TestRef(ref Int32 para)多一个[out]其它内容完全一样。

     在代码中将放开,会发现编译不通过,说明方法签名的区别如果仅仅是refout则无法实现方法的overload,也就是TestRef(ref Int32 para)TestRef(out Int32 para)这两个方法不能同时存在于同一个类型中。

在代码中将注释而将放开,会发现编译不通过,因为不能将一个未初始化的变量传给ref修饰参数的方法,但是传给out修饰参数的方法是可以的,但是在方法返回前一定要给out修饰的参数赋值。借用MS的一句话:

the ref and out keywords are treated differently at run-time, but they are treated the same at compile time.

 

4、结论

     (1)、有refout修饰参数的方法和普通方法在调用前的数据准备是不一样的,由L_0000: ldloca.s pL_0007: ldloc.0可以看到,前者是获取目标变量的内存地址,后者是获取目标变量的值,这就是所谓的传引用和传值。

     (2)、两个方法的区别仅仅是相同参数,一个使用的修饰符是ref,另一个是out,那么无法重载这两个方法,且分别编译它们得到的IL代码完全一样,只是方法签名中由out修饰的那个参数前会有个token[out]

(3) use of out parameters of the role: I do not care what the initial value of the variable is or I do not know what the initial value should be assigned or I just want to know the state of my method execution is completed ( eg: success or error and to the cause of the error ) , because all with out modification of the process parameters in this parameter must be reassigned, as MS mentioned: a method for selectively allowing a return value.

Reproduced in: https: //www.cnblogs.com/vivounicorn/archive/2009/09/17/1568242.html

Guess you like

Origin blog.csdn.net/weixin_34270606/article/details/93642172