8

文字列は参照型ですよね?私の理解では、文字列 ByVal をメソッドに渡す場合でも、ヒープ内の文字列への参照が渡されます。

すっごい……

String myTestValue = "NotModified";
TestMethod(myTestValue);
System.Diagnostics.Debug.Write(myTestValue); /* myTestValue = "NotModified" WTF? */

private void TestMethod(String Value)
{
    Value = "test1";
}

あるいは

Dim myTestValue As String = "NotModified"
TestMethod(myTestValue)
Debug.Print(myTestValue) /* myTestValue = "NotModified" WTF? */

Private Sub TestMethod(ByVal Value As String)
    Value = "test1"
End Sub

私は何が欠けていますか?そして、ボンネットの下で何が起こっているのですか?価値が変わっていたのに人生を賭けていただろう....

4

5 に答える 5

8

.NET では、参照型は「値による参照」で渡されます。これは、実際のパラメーターに別の値を割り当てても、実際には元の値が変更されないことを意味します (ByRef/ref を使用しない限り)。ただし、渡される実際のオブジェクトを変更するために行うことは、呼び出し元のメソッドが参照するオブジェクトを変更します。たとえば、次のプログラムを考えてみましょう。

void Main()
{
    var a = new A{I=1};
    Console.WriteLine(a.I);
    DoSomething(a);
    Console.WriteLine(a.I);
    DoSomethingElse(a);
    Console.WriteLine(a.I);
}

public void DoSomething(A a)
{
    a = new A{I=2};
}

public void DoSomethingElse(A a)
{
    a.I = 2;
}

public class A
{
    public int I;
}

出力:

1
1
2

メソッドはそのパラメーターに別の値をDoSomething割り当てましaたが、そのパラメーターはa、呼び出し元のメソッドからの元の場所へのローカル ポインターにすぎません。ポインターの値を変更しても、呼び出し元のメソッドのa値は変更されませんでした。ただし、DoSomethingElse実際には、参照されたオブジェクトの値の 1 つを変更しました。

他の回答者が何と言おうと、stringこのように例外的ではありません。すべてのオブジェクトがこのように動作します。

string多くのオブジェクトと異なる点は、不変であることです。実際に文字列を変更するために呼び出すことができる文字列のメソッド、プロパティ、またはフィールドはありません。.NET で文字列が作成されると、読み取り専用になります。

このようなことをすると:

var s = "hello";
s += " world";

... コンパイラはこれを次のように変換します。

// this is compiled into the assembly, and doesn't need to be set at runtime.
const string S1 = "hello"; 
const string S2 = " world"; // likewise
string s = S1;
s = new StringBuilder().Append(s).Append(S2).ToString();

この最後の行は新しい文字列を生成しますが、S1 と S2 はまだぶらぶらしています。それらがアセンブリに組み込まれた定数文字列である場合、それらはそこにとどまります。それらが動的に作成され、それらへの参照がなくなった場合、ガベージ コレクターはそれらを参照解除してメモリを解放できます。しかし重要なのは、S1 が実際には変更されていないことを理解することです。それを指す変数は、別の文字列を指すように変更されました。

于 2011-03-02T04:09:54.400 に答える
3

特に指定しない限り、すべてが値渡しされます。String を渡す場合、実際には参照を値で渡しています。

文字列の場合、文字列は不変であるため、これは大きな違いはありません。つまり、受け取った文字列を変更することはできません。ただし、他のクラスでは、値で渡されたオブジェクトを変更できます (String のように不変でない限り)。できないこと、および参照渡しでできることは、渡す変数を変更することです。

例:

Public Class Example
    Private Shared Sub ExampleByValue(ByVal arg as String)
        arg = "ByVal args can be modifiable, but can't be replaced."
    End Sub

    Private Shared Sub ExampleByRef(ByRef arg as String)
        arg = "ByRef args can be set to a whole other object, if you want."
    End Sub

    Public Shared Sub Main()
        Dim s as String = ""
        ExampleByValue(s)
        Console.WriteLine(s)  ''// This will print an empty line
        ExampleByRef(s)
        Console.WriteLine(s)  ''// This will print our lesson for today
    End Sub
End Class

現在、これは非常に慎重に使用する必要があります。値渡しがデフォルトであり、期待されているためです。特に VB では、参照渡しの際に常に明確になるとは限らず、何らかのメソッドが予期せず変数をいじり始めると、多くの問題が発生する可能性があります。

于 2011-03-02T04:14:41.030 に答える
2

あなたの例のように、参照型を含むすべての型はデフォルトで値渡しされます。つまり、参照のコピーが渡されます。したがって、そのようなオブジェクトを再割り当てしても、値渡しの場合は何の効果もありません。参照のコピーが指すものを変更しているだけです。やろうとしていることを達成するには、明示的に参照渡しする必要があります。

メソッドの外で効果が見られるのは、値渡しされたオブジェクトを変更した場合だけです。もちろん、文字列は不変であるため、これは実際には当てはまりません。

于 2011-03-02T04:03:08.037 に答える
0
  1. 文字列をメソッドに渡すと、参照のコピーが取得されます。したがって、Valueメモリ内の同じ文字列を参照するまったく新しい変数です。
  2. "test"文字列リテラルも実参照型オブジェクトとして作成されます。ソース コード内の単なる値ではありません。
  3. に割り当てる"test"ValueValue変数の参照が更新され"test"、元の文字列ではなく を参照します。この参照は単なるコピーであるため (ステップ 1 で見たように)、myTestValue関数の外側の変数は変更されず、元の文字列を参照します。

更新可能なプロパティを持つ型でテストすることで、これをよりよく理解できます。プロパティだけを変更すると、その変更は関数の外に表示されます。(この文字列で行っているように) オブジェクト全体を置き換えようとすると、関数の外では見えません。

于 2011-03-02T04:23:53.290 に答える
0

実際の参照ではなく、コピーを渡しています。

マイクロソフトのこの記事を読む

http://msdn.microsoft.com/en-us/library/s6938f28.aspx

于 2011-03-02T04:05:16.553 に答える