string
似ているが変更可能なタイプと比較すると役立ちますstring
。の短い例を見てみましょうStringBuilder
:
public void Caller1()
{
var builder = new StringBuilder("input");
Console.WriteLine("Before: {0}", builder.ToString());
ChangeBuilder(builder);
Console.WriteLine("After: {0}", builder.ToString());
}
public void ChangeBuilder(StringBuilder builder)
{
builder.Clear();
builder.Append("output");
}
これにより、次が生成されます。
Before: input
After: output
したがって、変更可能な型、つまり値を変更できる型の場合、その型への参照をメソッドのように渡してChangeBuilder
使用しないref
かout
、呼び出した後に値を変更したままにすることが可能であることがわかります。
builder
また、 で実際に別の値を設定したことは一度もないことに注意してChangeBuilder
ください。
対照的に、文字列で同じことを行うと、次のようになります。
public void Caller2()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
TryToChangeString(s);
Console.WriteLine("After: {0}", s);
}
public void TryToChangeString(string s)
{
s = "output";
}
これにより、次が生成されます。
Before: input
After: input
なんで?TryToChangeString
では、変数によって参照される文字列の内容を実際に変更していないため、まったく新しい文字列に置き換えていs
ます。 s
さらに、s
はローカル変数であるため、関数内TryToChangeString
で の値を置き換えても、関数呼び出しに渡された変数には影響しません。s
astring
はimmutableref
であるため、 orを使用しない限り、呼び出し元の文字列に影響out
を与える方法はありません。
最後に、最後の例は私たちが望むことを行いstring
ます:
public void Caller3()
{
var s = "input";
Console.WriteLine("Before: {0}", s);
ChangeString(ref s);
Console.WriteLine("After: {0}", s);
}
public void ChangeString(ref string s)
{
s = "output";
}
これにより、次が生成されます。
Before: input
After: output
このref
パラメーターは、実際には 2 つのs
変数を互いのエイリアスにします。あたかもそれらが同じ変数であるかのようです。