高级语言之所以成为高级语言,编译器付出了很多。params在给我们带来方便的同时,编译器也是贡献不少。
实例代码:
using System;
public class Test
{
public static void Main()
{
Console.WriteLine("结果1");
say("hello","world");
Console.WriteLine("结果2");
say("aaaa","sssss","ddddd");
Console.ReadKey();
}
public static void say(string str,string str2)
{
Console.WriteLine("single");
Console.WriteLine(str);
Console.WriteLine(str2);
}
public static void say(params string[] str)
{
Console.WriteLine("params");
foreach(string s in str)
{
Console.WriteLine(s);
}
}
}
说明下目的,
say("hello","world");
是为了验证在参数同时适配
public static void say(string str,string str2)
public static void say(params string[] str)
的时候,编译器是调用哪个函数。
say("aaaa","sssss","ddddd");
是为了察看params的运作过程
代码结果:
分析:
从结果1可看出在同时符合确定变量和可变变量的时候,编译器调用的是确定变量的函数,至于原因等说完params在提。
反编译这段代码。
注意参数,这里并没有出现params字样,说明到这个层级是不存在params了,接着看main函数。
.method public hidebysig static void Main() cil managed
{
.entrypoint
// Code size 79 (0x4f)
.maxstack 3
.locals init (string[] V_0)
IL_0000: ldstr bytearray (D3 7E 9C 67 31 00 ) // .~.g1.
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ldstr "hello"
IL_000f: ldstr "world"
IL_0014: call void Test::say(string,
string) // 结果1的调用
IL_0019: ldstr bytearray (D3 7E 9C 67 32 00 ) // .~.g2.
IL_001e: call void [mscorlib]System.Console::WriteLine(string)
IL_0023: ldc.i4.3
IL_0024: newarr [mscorlib]System.String
IL_0029: stloc.0
IL_002a: ldloc.0
IL_002b: ldc.i4.0
IL_002c: ldstr "aaaa"
IL_0031: stelem.ref
IL_0032: ldloc.0
IL_0033: ldc.i4.1
IL_0034: ldstr "sssss"
IL_0039: stelem.ref
IL_003a: ldloc.0
IL_003b: ldc.i4.2
IL_003c: ldstr "ddddd"
IL_0041: stelem.ref
IL_0042: ldloc.0
IL_0043: call void Test::say(string[]) //结果2的调用
IL_0048: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_004d: pop
IL_004e: ret
} // end of method Test::Main
从结果1可以清楚地看到调用的是确定参数函数,往下的IL_0024构建了一个数组,然后在一个个的把参数推送进数组,最后调用了say(string[] )函数.
结论:
params的实现只是将单个的参数打包成数组,,调用数组参数函数,事实上你并不能同时声明,say(string[])和say(params string[]),会提示已存在.在这里也能解释为什么在既可变参,也可定参的情况下使用定参的原因了.使用变参需要额外的代码打包参数.