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変数を互いのエイリアスにします。あたかもそれらが同じ変数であるかのようです。