C#使用params关键字的结果不一致

时间:2012-09-21 07:30:49

标签: c# pass-by-reference params pass-by-value

考虑以下方法:

static void ChangeArray(params string[] array) {

    for (int i = 0; i < array.Length; i++) 
        array[i] = array[i] + "s";
}

如果我将其称为传递字符串数组,则此方法有效:

string[] array = {"Michael", "Jordan"} // will become {"Michaels", "Jordans"}
ChangeArray(array);

但是如果我使用字符串参数调用它将无法工作:

string Michael = "Michael";
string Jordan = "Jordan";
ChangeArray(Michael, Jordan); // This will NOT change the values of the variables

据我所知,编译器会将Michael和Jordan包装在一个数组上,所以两种情况下结果不一样吗?

3 个答案:

答案 0 :(得分:23)

你的第二个例子基本上是:

string Michael = "Michael";
string Jordan = "Jordan";
{
    var tmp = new string[] {Michael, Jordan};
    ChangeArray(tmp);
}

如此;实际上,tmp 中的值已经更改了......但之后丢弃了tmp,因此您没有看到任何内容。 params 模仿ref - 它不会按位置更新回原始变量。或者在代码中,以下内容:

string Michael = "Michael";
string Jordan = "Jordan";
{
    var tmp = new string[] {Michael, Jordan};
    ChangeArray(tmp);
    Michael = tmp[0];
    Jordan = tmp[1];
}

如果您需要它的行为,那么代码就像那样 - 或者使用带有ref参数的重载。

答案 1 :(得分:5)

原因是string是一个不可变类型 - 你传入包含在数组中的string个实例。该数组现在包含两个新字符串(具有与原始字符串相同但不同实例的值)。更改阵列时,这些副本将被丢弃,阵列插槽将保留一个新字符串。当函数返回时,临时数组将被丢弃。因此,您的原始输入字符串永远不会被修改(它们无论如何都不可能,因为string是 - 再次 - 不可变的。)

编辑我在评论中提到Lee的论点之后对这个答案进行了编辑(我将保留答案,只是为了完成以下讨论)。不可变部分确实与问题无关。主要的根本问题是对被丢弃的临时数组进行了更改。

答案 2 :(得分:2)

这很奇怪(我不知道这一点),但是as specified

  

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

     

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

     

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