为什么将null传递给params方法导致null参数数组?

时间:2021-07-22 21:32:08

I have a method that uses the params keyword, like so:

我有一个使用params关键字的方法,如下所示:

private void ParamsMethod(params string[] args)
{
    // Etc...
}

Then, I call the method using various combinations of arguments:

然后,我使用各种参数组合调用该方法:

                            // 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"

I understand all of the cases, except for the second one. Can someone explain why ParamsMethod(null) causes args to be null, instead of an array with one null element?

我了解所有案例,除了第二个案例。有人可以解释为什么ParamsMethod(null)导致args为null,而不是具有一个null元素的数组?

5 个解决方案

#1


30  

A params parameter is only meant to provide a convenient way of specifying values - you can still pass an array reference directly.

params参数仅用于提供指定值的便捷方式 - 您仍然可以直接传递数组引用。

Now, null is convertible to either string[] or string, so both interpretations are valid - it's up to the spec which is preferred. The spec states in section 10.6.1.4 that:

现在,null可以转换为string []或string,因此两种解释都是有效的 - 它取决于首选的规范。该规范在第10.6.1.4节中指出:

  • The argument given for a parameter array can be a single expression that is implicitly convertible to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

    为参数数组提供的参数可以是可隐式转换为参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。

  • Alternatively, [...]

    或者,[...]

In other words, the compiler checks to see whether the argument is valid as the "normal" parameter type first, and only builds an array if it absolutely has to.

换句话说,编译器首先检查参数是否有效作为“普通”参数类型,并且只有在绝对必须时才构建数组。

#2


8  

See the C# specification, section 10.6.1.4 Parameter arrays:

请参阅C#规范,第10.6.1.4节参数数组:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

参数数组允许在方法调用中以两种方式之一指定参数:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.
  • 为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。
  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.
  • 或者,调用可以为参数数组指定零个或多个参数,其中每个参数是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。

Since null is implicitly convertible to string[], it will be used as the array.

由于null可以隐式转换为string [],因此它将用作数组。

Furthermore:

此外:

When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (§7.5.3.1). The expanded form of a method is available only if the normal form of the method is not applicable and only if a method with the same signature as the expanded form is not already declared in the same type.

执行重载解析时,具有参数数组的方法可以以其正常形式或以其扩展形式(第7.5.3.1节)应用。只有在方法的正常形式不适用且仅与扩展形式具有相同签名的方法尚未在同一类型中声明时,方法的扩展形式才可用。

which clarifies that the compiler indeed first tries to use the method with an array argument (normal form) before it tries using the argument as an array element (expanded form).

这说明编译器在尝试将参数用作数组元素(扩展形式)之前,确实首先尝试使用带有数组参数(普通形式)的方法。

#3


3  

The reason for this is that you can pass an array of the appropriate type to a params argument. Since null can be converted to any type, and the array syntax takes precedence, you get null as the value of your parameter.

原因是您可以将适当类型的数组传递给params参数。由于null可以转换为任何类型,并且数组语法优先,因此您将获得null作为参数的值。

Explicitly casting it to string, of course, makes it become an element of the array rather than the array itself.

当然,将它显式地转换为字符串会使它成为数组的元素而不是数组本身。

You can try it and see:

你可以尝试看看:

private void DoSomething(params IEnumerable[] arr) {
    // ...
}

...

DoSomething(new IEnumerable[] {new int[] {}}); // arr[0] isn't IEnumerable[], it's int[].

And here's an online demo.

这是一个在线演示。

#4


3  

You can pass an array to a params parameter - in fact, it is preferable (I.e. if you pass an object[] to a method that takes params object[], it is the entire parameter, not just the single element). Null is valid as an assignment to an array, so - that binding wins.

你可以将数组传递给params参数 - 事实上,它更可取(即,如果你将一个object []传递给一个采用params object []的方法,它就是整个参数,而不仅仅是单个元素)。 Null作为数组的赋值有效,因此 - 绑定获胜。

Basically, you'll ned to be more explicit.

基本上,你会更明确。

#5


2  

From the language specification:

从语言规范:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

参数数组允许在方法调用中以两种方式之一指定参数:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

    为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。

  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

    或者,调用可以为参数数组指定零个或多个参数,其中每个参数是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。

Since null in ParamsMethod(null) can be implicitly converted to (string[])null, the first rule is the one that gets applied.

由于ParamsMethod(null)中的null可以隐式转换为(string [])null,因此第一个规则是应用的规则。

#1


30  

A params parameter is only meant to provide a convenient way of specifying values - you can still pass an array reference directly.

params参数仅用于提供指定值的便捷方式 - 您仍然可以直接传递数组引用。

Now, null is convertible to either string[] or string, so both interpretations are valid - it's up to the spec which is preferred. The spec states in section 10.6.1.4 that:

现在,null可以转换为string []或string,因此两种解释都是有效的 - 它取决于首选的规范。该规范在第10.6.1.4节中指出:

  • The argument given for a parameter array can be a single expression that is implicitly convertible to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

    为参数数组提供的参数可以是可隐式转换为参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。

  • Alternatively, [...]

    或者,[...]

In other words, the compiler checks to see whether the argument is valid as the "normal" parameter type first, and only builds an array if it absolutely has to.

换句话说,编译器首先检查参数是否有效作为“普通”参数类型,并且只有在绝对必须时才构建数组。

#2


8  

See the C# specification, section 10.6.1.4 Parameter arrays:

请参阅C#规范,第10.6.1.4节参数数组:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

参数数组允许在方法调用中以两种方式之一指定参数:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.
  • 为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。
  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.
  • 或者,调用可以为参数数组指定零个或多个参数,其中每个参数是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。

Since null is implicitly convertible to string[], it will be used as the array.

由于null可以隐式转换为string [],因此它将用作数组。

Furthermore:

此外:

When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (§7.5.3.1). The expanded form of a method is available only if the normal form of the method is not applicable and only if a method with the same signature as the expanded form is not already declared in the same type.

执行重载解析时,具有参数数组的方法可以以其正常形式或以其扩展形式(第7.5.3.1节)应用。只有在方法的正常形式不适用且仅与扩展形式具有相同签名的方法尚未在同一类型中声明时,方法的扩展形式才可用。

which clarifies that the compiler indeed first tries to use the method with an array argument (normal form) before it tries using the argument as an array element (expanded form).

这说明编译器在尝试将参数用作数组元素(扩展形式)之前,确实首先尝试使用带有数组参数(普通形式)的方法。

#3


3  

The reason for this is that you can pass an array of the appropriate type to a params argument. Since null can be converted to any type, and the array syntax takes precedence, you get null as the value of your parameter.

原因是您可以将适当类型的数组传递给params参数。由于null可以转换为任何类型,并且数组语法优先,因此您将获得null作为参数的值。

Explicitly casting it to string, of course, makes it become an element of the array rather than the array itself.

当然,将它显式地转换为字符串会使它成为数组的元素而不是数组本身。

You can try it and see:

你可以尝试看看:

private void DoSomething(params IEnumerable[] arr) {
    // ...
}

...

DoSomething(new IEnumerable[] {new int[] {}}); // arr[0] isn't IEnumerable[], it's int[].

And here's an online demo.

这是一个在线演示。

#4


3  

You can pass an array to a params parameter - in fact, it is preferable (I.e. if you pass an object[] to a method that takes params object[], it is the entire parameter, not just the single element). Null is valid as an assignment to an array, so - that binding wins.

你可以将数组传递给params参数 - 事实上,它更可取(即,如果你将一个object []传递给一个采用params object []的方法,它就是整个参数,而不仅仅是单个元素)。 Null作为数组的赋值有效,因此 - 绑定获胜。

Basically, you'll ned to be more explicit.

基本上,你会更明确。

#5


2  

From the language specification:

从语言规范:

A parameter array permits arguments to be specified in one of two ways in a method invocation:

参数数组允许在方法调用中以两种方式之一指定参数:

  • The argument given for a parameter array can be a single expression that is implicitly convertible (§6.1) to the parameter array type. In this case, the parameter array acts precisely like a value parameter.

    为参数数组提供的参数可以是可隐式转换(第6.1节)到参数数组类型的单个表达式。在这种情况下,参数数组的作用与值参数完全相同。

  • Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (§6.1) to the element type of the parameter array. In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

    或者,调用可以为参数数组指定零个或多个参数,其中每个参数是一个可隐式转换(第6.1节)到参数数组的元素类型的表达式。在这种情况下,调用创建参数数组类型的实例,其长度对应于参数的数量,使用给定的参数值初始化数组实例的元素,并使用新创建的数组实例作为实际参数。

Since null in ParamsMethod(null) can be implicitly converted to (string[])null, the first rule is the one that gets applied.

由于ParamsMethod(null)中的null可以隐式转换为(string [])null,因此第一个规则是应用的规则。