能否在函数中修改string类型的函数参数
string test = “string”;
this.funString(test);
Console.WriteLine(test); //依然输出”string”
private void funString(string input)
{
input = “new string”;
}
如果换一种写法,答案就很明了:
string a = “string a”;
string b = a;
a = “new string a”;
Console.WriteLine(a); // new string a
Console.WriteLine(b); // string a
这是由于string 虽然是reference 类型,但:
A String object is called immutable (read-only) because its value cannot be modified once it has been created.
Methods that appear to modify a String object actually return a new String object that contains the modification.
funString中的input是test的一个reference, 但修改input不会修改test, 就像上个例子中的a和b.
此时生成的IL代码为:
.method private hidebysig instance void funString(string input) cil managed
{
// Code size 9 (0x9)
.maxstack 8
IL_0000: nop
IL_0001: ldstr “new string” //把 “new string”压栈
IL_0006: starg.s input //把栈顶元素即 “new string” 赋给input
IL_0008: ret
} // end of method Form1::funString
如果把代码写成
private void funRefString(ref string input)
{
input = “new string”;
}
则会生成代码
.method private hidebysig instance void funRefString(string& input) cil managed
{
// Code size 9 (0x9)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1 //把1号参数,即input压栈, 这是和funString的最核心的不同, funString通过忽略这条指令来
//保证string的immutable
//同时,此处没有ldind.ref 这条指令,对string进行了特殊处理
IL_0002: ldstr “new string” //把 “new string”压栈
IL_0007: stind.ref //把栈顶的两个元素弹出来,进行ref 赋值.
IL_0008: ret
} // end of method Form1::funRefString
此时直接修改了test的值.
如果fun的参数是其他reference类型,使用或不使用ref关键字生成的代码也有所不同,但执行结果完全相同:
.method private hidebysig instance void funForm(class [System.Windows.Forms]System.Windows.Forms.Form f) cil managed
{
// Code size 14 (0xe)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldstr “new Form Text”
IL_0007: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
IL_000c: nop
IL_000d: ret
} // end of method Form1::funForm
.method private hidebysig instance void funRefForm(class [System.Windows.Forms]System.Windows.Forms.Form& f) cil managed
{
// Code size 15 (0xf)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldind.ref //这是唯一的不同, 其中用是把栈顶元素弹出,再把其address压栈,对于reference type来说,没有任何意义.
IL_0003: ldstr “new Form Text”
IL_0008: callvirt instance void [System.Windows.Forms]System.Windows.Forms.Control::set_Text(string)
IL_000d: nop
IL_000e: ret
} // end of method Form1::funRefForm
