3

使用此代码:

 void SomeMethod(string str)
 {
      string tmpStr = ... Read some value from file ... 

      if( !tmpStr.Empty() ) 
           str = tmpStr;

 }

当我使用刚刚在主子例程中创建的简单字符串调用此方法时:

 string localString = "";
 SomeMethod( localString );

localString当我在调试中看到方法SomeMethod中的变量tmpStr不为空并且方法str中的变量充满字符时,我返回的值是一个空事件。

如果我将SomeMethod签名更改为:

SomeMethod(ref string str) 

我看到了正确的结果。

但是 string 是一个引用类型,那么为什么在这种情况下我需要用 发送它ref呢?以及为什么我只有在打电话时才会得到预期的结果:

SomeMethod(string str) 
4

4 回答 4

7

不仅字符串是不可变的,而且虽然string是引用类型,但引用本身不是。也就是说,您传递的是string按引用,但引用本身是按值传递的。

因此,对于引用类型,您可以修改参数所引用的对象(只要它是可修改的),但您不能修改参数所引用的内容,除非您通过引用传递它。

因此,当您尝试更改string变量所指的内容时:

str = tmpStr;

它改变了str本地引用的内容,但不影响原始参数所localString引用的内容。

这样想,假设参数localString引用位置 1000 的对象:

localString 
+---------------+                      1000
|      1000     |   -----------------> +---------------+
+---------------+                      | Count: 1      |
                                       | Value: ""     |
                                       +---------------+

然后当我们传递localString给该方法时,它会创建引用的副本(as str)并更新引用计数...

localString 
+---------------+                      1000
|      1000     |   -----------------> +---------------+
+---------------+                      | Count: 2      |
                                       | Value: ""     |
str                                    +---------------+
+---------------+                        ^
|      1000     |   ---------------------+
+---------------+

然后,当您将 str 分配给新字符串时,它会修改引用str,但不会localString

localString
+---------------+                      1000
|      1000     |   -----------------> +---------------+
+---------------+                      | Count: 1      |
                                       | Value: ""     |
str                                    +---------------+
+---------------+                          2500
|      2500     |   ---------------------> +---------------+
+---------------+                          | Count: 1      |
                                           | Value: ...    |
                                           +---------------+

所以你的修改str只改变了str引用的内容,而不是原始的引用localString,如果你想改变那个,那么你通过引用传递,这意味着这str是对原始参数的引用(很像 ptr 到 ptr):

localString
+---------------+                      1000
|      2500     |  ------------------> +---------------+
+---------------+                      | Count: 2      |
        ^                              | Value: ""     |
str     |                              +---------------+
+---------------+       
|               |       
+---------------+                                                              

现在,当您更改str它时,它也会更改参考localString

localString
+---------------+                      1000
|      1000     |  -----+              +---------------+
+---------------+       |              | Count: 0      |
        ^               |              | Value: ""     |
str     |               |              +---------------+
+---------------+       |                  2500
|               |       +----------------> +---------------+
+---------------+                          | Count: 1      |
                                           | Value: ...    |
                                           +---------------+

然后,当然,原始字符串(假设在这个例子中没有其他引用它)可以被垃圾收集......

所以,如果你真的想修改string参数,通过refor传递它out,或者你可以返回新的变异版本,或者存储在实例成员中(尽管传递实例成员是更高阶的耦合,可能会导致其他问题...)。

于 2012-09-05T20:13:32.180 回答
2

如果您不使用 ref 进行所有更改,但将进行分配,这是因为方法主体内的 str 是作为参数传递的变量的副本,并且它指向内存中的同一个实例,所以如果您调用方法或访问字段,则它位于同一个实例上,但如果您将另一个实例分配给 str 它仅开始指向另一个实例。但由于 str 只是用作参数的变量的副本,因此不会更改参数。如果您使用 ref 则不会创建副本并使用相同的指针。

于 2012-09-05T20:18:29.837 回答
1

这应该做你想要的:

string SomeMethod()
{
      string tmpStr = ... Read some value from file ... 

      if( !tmpStr.Empty() ) 
           str = tmpStr;

         return str;
}

string localString = SomeMethod();
于 2012-09-05T20:13:48.510 回答
1

“您不能更改引用本身的值;也就是说,您不能使用相同的引用来为新类分配内存并让它在块之外持续存在。”

从这个网站: http: //msdn.microsoft.com/en-us/library/0f66670z (v=vs.71).aspx#vclrfpassingmethodparameters_example4

所以你只是改变块内的引用。有两种方法可以解决这个问题。1. 使用您发现的 ref 关键字传递。2. 正如其他人所建议的那样;更改方法以返回一个字符串,然后像这样声明您的新字符串:

String localString = SomeMethod();
于 2012-09-05T20:24:39.247 回答