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) 

正しい結果が表示されます。

しかし、文字列は参照型なので、この場合、文字列を一緒に送信する必要があるのはなぜ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もののみを変更した場合、それを変更たい場合は、参照渡しします。つまり、元の引数への参照になります (ptr から ptr に似ています)。strlocalStringstr

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

ここで、str変更すると参照も変更localStringされます。

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

そしてもちろん、元の文字列 (この例のように他に何も参照されていないと仮定) は、ガベージ コレクトすることができます...

そのため、本当にstringパラメーターを変更したい場合は、refまたはで渡すか、変更されoutた新しいバージョンを返すか、インスタンス メンバーに格納します (ただし、pass-by-instance-member はカップリングの高次であり、他のエラーを引き起こす可能性があります)。問題...)。

于 2012-09-05T20:13:32.180 に答える
2

すべての変更をrefを使用せずに、割り当てが行われる場合、メソッドの本体内のstrは引数として渡された変数のコピーであり、メモリ内の同じインスタンスを指しているためです。メソッドまたはアクセスフィールドを呼び出す場合、それは同じインスタンス上にありますが、別のインスタンスをstrに割り当てると、そのインスタンスは別のインスタンスを指すようになります。ただし、strは引数として使用される変数のコピーにすぎないため、引数は変更されません。refを使用する場合、コピーは作成されず、同じポインターが使用されます。

于 2012-09-05T20:18:29.837 に答える
1

「参照自体の値を変更することはできません。つまり、同じ参照を使用して新しいクラスにメモリを割り当て、ブロックの外に保持することはできません。」

このサイトから: http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx#vclrfpassingmethodparameters_example4

したがって、ブロック内の参照のみを変更しています。これには 2 つの方法があります。1. 発見したように ref キーワードで渡します。2. 他の誰かが示唆したように; 文字列を返すようにメソッドを変更し、次のように新しい文字列を宣言します。

String localString = SomeMethod();
于 2012-09-05T20:24:39.247 に答える
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 に答える