我有一个使用params
关键字的方法,如下所示:
private void ParamsMethod(params string[] args)
{
// Etc...
}
然后,我使用各种参数组合调用该方法:
// Within the method, args is...
ParamsMethod(); // - a string array with no elements
ParamsMethod(null); // - null (Why is this?)
ParamsMethod((string)null); // - a string array with one element: null
ParamsMethod(null, null); // - a string array with two elements: null and null
ParamsMethod("s1"); // - a string array with one element: "s1"
ParamsMethod("s1", "s2"); // - a string array with two elements: "s1" and "s2"
我了解所有案例,除了第二个案例。有人可以解释为什么ParamsMethod(null)
导致args
成为null
而不是具有一个空元素的数组?
答案 0 :(得分:30)
params
参数仅用于提供指定值的便捷方式 - 您仍然可以直接传递数组引用。
现在,null
可以转换为string[]
或string
,因此这两种解释都是有效的 - 这取决于首选的规范。该规范在第10.6.1.4节中指出:
为参数数组提供的参数可以是可隐式转换为参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。
或者,[...]
换句话说,编译器首先检查参数是否有效作为“普通”参数类型,并且只有在必要时才构建数组。
答案 1 :(得分:8)
请参阅C#规范, 10.6.1.4参数数组:
部分参数数组允许在方法调用中以两种方式之一指定参数:
- 为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用就像一个值参数。
- 或者,调用可以为参数数组指定零个或多个参数,其中每个参数都是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。 / LI>
由于null
可隐式转换为string[]
,因此它将用作数组。
此外:
执行重载解析时,带参数数组的方法可以采用其正常形式或扩展形式(第7.5.3.1节)。只有当方法的正常形式不适用且且只有与扩展形式具有相同签名的方法尚未在同一类型中声明时,方法的扩展形式才可用。
它澄清了编译器确实首先尝试使用带有数组参数(普通形式)的方法,然后再尝试将参数用作数组元素(扩展形式) )。
答案 2 :(得分:3)
这样做的原因是您可以将适当类型的数组传递给params
参数。由于null
可以转换为任何类型,并且数组语法优先,因此您可以获得null
作为参数的值。
当然,将它显式地转换为string
会使它成为数组的元素而不是数组本身。
你可以尝试看看:
private void DoSomething(params IEnumerable[] arr) {
// ...
}
...
DoSomething(new IEnumerable[] {new int[] {}}); // arr[0] isn't IEnumerable[], it's int[].
答案 3 :(得分:3)
你可以将数组传递给params参数 - 事实上,它更可取(即如果你将一个object []传递给一个采用params object []的方法,那就是整个参数,而不仅仅是单个元素)。 Null作为数组的赋值有效,因此 - 该绑定获胜。
基本上,你会更加明确。
答案 4 :(得分:2)
来自语言规范:
参数数组允许在方法调用中以两种方式之一指定参数:
为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。
或者,调用可以为参数数组指定零个或多个参数,其中每个参数都是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。 / p>
由于null
中的ParamsMethod(null)
可以隐式转换为(string[])null
,因此第一条规则是应用的规则。