字符串的行为类似于值类型

时间:2012-02-22 16:46:20

标签: c# function value-type reference-type

我刚写了一个函数,我不明白为什么我得到的结果是:

private void ReplaceIfEmpty(string originalValue, string newValue)
{
  if (string.IsNullOrWhitespace(originalValue))
  {
    originalValue= newValue;
  }
}

当我调用此函数时,原始值不会更新。我的理解是字符串是一个类,因此它是一个引用类型,因此我传入的值应该更新。你能解释一下为什么不是吗?

4 个答案:

答案 0 :(得分:19)

这与参考类型与值类型无关。

您正在更改参数的值:

originalValue= newValue;

对于没有refout修饰符的“普通”参数,该更改永远不会可见。

请参阅我的article on parameter passing以获取更多信息,以及我在reference types and value types上的文章,以确保您了解为什么有时“看起来”类似于默认情况下通过引用传递引用类型。 (它们不是:默认情况下所有参数都是按值传递的,只是对于引用类型,参数值是引用,而不是对象,因此对对象的更改仍然是可见的来电者。)

所以可以使originalValue成为ref参数 - 但最好让方法返回string。我一般不愿意使用ref参数;没有它们,代码通常更容易理解。

答案 1 :(得分:7)

您将引用传递给字符串。您没有传递对变量的引用。如果您想更改变量,那么您可以这样做:

private void ReplaceIfEmpty(ref string originalValue, string newValue)  ...

这种差异经常让人感到困惑。这样想吧。想象两个房子,而不是想象一个字符串。现在想象两张纸上有那些房子的地址;这些是引用到房子。现在想象四个抽屉,每个抽屉都包含一张纸。抽屉标记为p,q,x和y:

void M(House x, House y)
{
    x = y;
}
...
House p = new House("123 Sesame Street");
House q = new House("1600 Pennsylvania Avenue");
M(p, q);

这个程序做什么?你把一张纸说成芝麻街" 123芝麻街"在抽屉里。你把一张纸说成宾夕法尼亚大道" 1600宾夕法尼亚大道"在抽屉q。

您在纸盒p中复印纸张并将副本放入抽屉x中。您在抽屉q中制作纸张的复印件并将副本放入抽屉y中。然后你打电话给M.M制作了抽屉里的东西的复印件,并把它放在抽屉里。 抽屉p不受影响

现在考虑一下这个案例:

void M(ref House r, House s)
{
    r = s;
}
...
House p = new House("123 Sesame Street");
House q = new House("1600 Pennsylvania Avenue");
M(ref p, q);

这个程序做什么?你把一张纸说成芝麻街" 123芝麻街"在抽屉里。你把一张纸说成宾夕法尼亚大道" 1600宾夕法尼亚大道"在抽屉q。

你在抽屉p上贴上了一张粘滞便笺,上面写着"这个抽屉也被称为r"。

您在纸盒q中复印纸张并将副本放入纸盒中。

然后你打电话给M.M复印抽屉里的东西并把它放在抽屉里,和抽屉p 相同。

有意义吗?

答案 2 :(得分:5)

您没有更改作为参数originalValue传递的变量的值,您正在尝试为其分配一个新实例,这对于引用意味着该变量指向一个新引用 - 更新一个 reference 您需要通过ref传递字符串 - 默认情况下,引用按值传递,因此您传递的变量永远不会更新:

private void ReplaceIfEmpty(ref string originalValue, string newValue)
{
  if (string.IsNullOrWhitespace(originalValue))
  {
     originalValue = newValue;
  }
}

更好的方法是返回新字符串:

private string ReplaceIfEmpty(string originalValue, string newValue)
{
   if (string.IsNullOrWhitespace(originalValue))
      return newValue;
   else
      return originalValue;
}

或者更方便使它成为一种扩展方法:

public static string ReplaceIfEmpty(this string originalValue, 
                                    string replaceValue)
{
   if (string.IsNullOrWhitespace(originalValue))
      return replaceValue;
   else
      return originalValue;
}

答案 3 :(得分:0)

当您执行以下任务时:

originalValue = newValue;

您没有更改originalValue引用的字符串值,而是将originalValue的值更改为指向与newValue相同的位置。

字符串是不可变的,在设置后无法修改,只能重新分配。