16

给定以下方法:

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 包装在一个数组中,所以两种情况下的结果不应该相同吗?

4

3 回答 3

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参数的重载。

于 2012-09-21T07:33:52.783 回答
5

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

编辑根据李在评论中的论点,我对此答案进行了编辑(我将保留答案,只是为了保持以下讨论的完整)。不可变部分确实与问题无关。主要的潜在问题是对丢弃的临时数组进行了更改。

于 2012-09-21T07:34:41.400 回答
2

这很奇怪(我不知道),但正如指定的那样

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

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

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

于 2012-09-21T07:35:06.293 回答