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:
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()
{
.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)
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldc.i4.2
L_0002: stind.i4
L_0003: ret
}
(3) TestRef (Int32 para)
{
.maxstack 8
L_0000: ldc.i4.1
L_0001: starg.s para
L_0003: ret
}
(4) TestRef(out Int32 para)
{
.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)””
{
private void InvokeTest()
{
Test( 1 );
}
private void Test(Int32 i)
{
}
}
{
.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],其它内容完全一样。
在代码中将②放开,会发现编译不通过,说明方法签名的区别如果仅仅是ref和out则无法实现方法的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)、有ref和out修饰参数的方法和普通方法在调用前的数据准备是不一样的,由L_0000: ldloca.s p和L_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