.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 が実際には変更されていないことを理解することです。それを指す変数は、別の文字列を指すように変更されました。