簡単に言えば、ref
キーワードは、呼び出されたメソッドが呼び出しサイトで参照を操作できるようにします。これが の完全な目的ですref
。
何が起こるかというと、Vodka
返されたときに、新しい文字列インスタンスsss
に置き換えられています。元のインスタンスは更新されません。モディファイヤなしでは、これは不可能です。ref
これについて話すときによく混乱するのは、参照型を扱うときにパラメータを値と参照で渡すという概念について考えるときです。文字列 (参照型)を値で渡す場合、実際に渡すのは何ですか? 変数の値を渡します。この場合、値は文字列への参照です。したがって、その値を渡すと、呼び出し元のメソッドはその値を使用して文字列にアクセスできます。ただし、パラメーターは値で渡されるため、渡されるのは値そのもの (基本的には参照のコピー) であり、値を格納するメモリー位置へのポインターではありません。これが、呼び出し元のメソッドが呼び出しサイトでインスタンスを置き換えることができない理由です。
パラメータを値ではなく参照で渡す場合、呼び出されたメソッドは値が格納されているメモリ位置にアクセスします (値は文字列への参照であることを覚えておいてください)。これは、呼び出されたメソッドがこの値を更新して、呼び出しサイトの変数に別の文字列への参照を含めることができることを意味します。
更新
あなたのコメントから例を分析してみましょう(名前は無実を保護するために変更されています):
class SomeClass
{
public int Value { get; set; }
}
class DoWork
{
public static void DoOne(SomeClass c) { c.Value = c.Value + 1; }
public static void DoTwo(ref SomeClass c) { c.Value = c.Value + 2; }
}
SomeClass
参照型です。これは、そのようなインスタンスを渡す任意のコード (明確にするために、参照型の実際のインスタンスを渡すことはなく、インスタンスへの参照を渡す) は、そのインスタンス内のデータを操作できることを意味します*。これは、メソッドを呼び出したり、プロパティ値を設定したりできることを意味し、これがもたらす状態の変化は呼び出しサイトでも表示されます。ref
キーワードはそれには影響しません。したがって、サンプルでは、ref
キーワードに違いはありません。ただし、次の変更を検討してください。
class DoWork
{
public static void DoOne(SomeClass c)
{
c = new SomeClass();
c.Value = 1;
}
public static void DoTwo(ref SomeClass c)
{
c = new SomeClass();
c.Value = 2;
}
}
では、次のように呼び出します。
var temp = new SomeClass() { Value = 42 };
DoWork.DoOne(temp);
Console.WriteLine(temp.Value); // prints 42
DoWork.DoTwo(ref temp);
Console.WriteLine(temp.Value); // prints 2
ここで、両方のメソッドが操作対象の新しいSomeClass
インスタンスを作成します。値によって渡された参照を取得するためDoOne
、参照の独自のプライベート コピーを更新して、新しいインスタンスを指すようにします。当然、この変更は呼び出しサイトでは見られません。
一方、DoTwo
は参照渡しで参照を取得するため、新しいインスタンスを作成して に割り当てるとc
、呼び出しサイトが使用しているのと同じメモリ位置を更新するため、temp
内部で作成された新しいインスタンスを参照していますDoTwo
。
要約すると、参照型の場合、使用する必要があるref
のは、呼び出されたメソッドを有効にして、渡されたインスタンス自体を置き換える場合のみです。そのインスタンスの状態のみを操作したい場合、参照型は常にそれを許可します。
Cody Gray が、Jon Skeet のC#でのパラメータ受け渡しへのリンクを投稿しました。まだ読んでいない場合は、読んでください。これは、これらのことを説明するのに非常に優れています (さらに、値の型も扱います)。
* (文字列のように型が不変でない限り、それはまったく別の話です...)