ref (C# リファレンス)
ref
キーワードは、次のコンテキストで使用できます。
- メソッド シグネチャとメソッドの呼び出しで、参照によってメソッドに引数を渡します。 詳細については、「参照渡しで引数を渡す」を参照してください。
- メソッド シグネチャで、参照渡しで呼び出し元に値を返します。 詳細については、参照戻り値に関するページを参照してください。
- ローカル変数の宣言で、参照変数を宣言する目的で。 詳細については、「宣言ステートメント」の記事の「参照変数」セクションを参照してください。
- 条件付き ref 式または ref 代入演算子の一部として。
struct
宣言で、ref struct
を宣言する目的で。 詳細については、ref
構造体の種類の記事を参照してください。ref struct
定義で、ref
フィールドを宣言します。 詳細については、「ref
構造体型」の記事の「ref
フィールド」セクションを参照してください。
参照渡しで引数を渡す
メソッドのパラメーター リストで使用した場合、ref
キーワードは、引数を値ではなく、参照によって渡すことを示します。 ref
キーワードは、仮パラメーターを引数 (変数にする必要があります) の別名にします。 つまり、パラメーターに対するすべての操作は引数に対して行われます。
たとえば、呼び出し元からローカル変数式または配列要素のアクセス式が渡されるとします。 また、呼び出されるメソッドでは、ref パラメーターが参照するオブジェクトを置き換えることができます。 その場合は、メソッドから制御が戻ったとき、呼び出し元のローカル変数または配列要素によって参照されるのは、新しいオブジェクトとなります。
注意
参照渡しで渡すという概念と参照型の概念とを混同しないでください。 2 つの概念は同じではありません。 メソッドのパラメーターは、値型か参照型かどうかに関係なく、ref
によって変更できます。 参照渡しで渡される場合、値型はボックス化されません。
ref
パラメーターを使用するには、メソッド定義と呼び出し元のメソッドの両方が、次の例に示すように ref
キーワードを明示的に使用する必要があります。 (例外として、COM 呼び出しを行う場合は、呼び出し元のメソッドで ref
を省略できます)。
void Method(ref int refArgument)
{
refArgument = refArgument + 44;
}
int number = 1;
Method(ref number);
Console.WriteLine(number);
// Output: 45
ref
または in
パラメーターに渡す引数は、渡す前に初期化する必要があります。 この要件は、引数を渡す前に明示的に初期化する必要がない out パラメーターの場合とは異なります。
クラスのメンバーは、ref
、in
、または out
のみが異なるシグネチャを持つことはできません。 1 つの型の 2 つのメンバー間の唯一の違いが、1 つには ref
パラメーターが存在し、もう 1 つには out
または in
パラメーターが存在することである場合、コンパイラ エラーが発生します。 たとえば、次のコードはコンパイルされません。
class CS0663_Example
{
// Compiler error CS0663: "Cannot define overloaded
// methods that differ only on ref and out".
public void SampleMethod(out int i) { }
public void SampleMethod(ref int i) { }
}
ただし、次の例に示すように、1 つのメソッドに ref
、in
または out
パラメーターがあり、もう 1 つには値渡しされるパラメーターがある場合、メソッドをオーバーロードすることができます。
class RefOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(ref int i) { }
}
非表示やオーバーライドなど、シグネチャの一致が必要な他の状況では、in
、ref
、out
はシグネチャの一部であり、互いに一致しません。
プロパティは変数ではありません。 それらはメソッドであり、ref
パラメーターに渡すことはできません。
次の種類のメソッドには、ref
、in
、out
キーワードを使用することはできません。
- async 修飾子を使用して定義した Async メソッド。
- yield return または
yield break
ステートメントを含む Iterator メソッド。
拡張メソッドには、これらのキーワードの使用に関する制限もあります。
- 拡張メソッドの最初の引数では、
out
キーワードを使用できません。 - 拡張メソッドの最初の引数が構造体ではない場合、または構造体として制約されていないジェネリック型である場合、その引数で
ref
キーワードを使用することはできません。 - 最初の引数が構造体である場合を除き、
in
キーワードは使用できません。 ジェネリック型では、構造体として制約されている場合であっても、in
キーワードを使用することはできません。
参照渡しで引数を渡す:使用例
前の例は、参照によって値型を渡す例でした。 ref
キーワードを使用して、参照渡しで参照型を渡すこともできます。 参照型を参照渡しで渡すと、呼び出されたメソッドは、参照パラメーターが呼び出し元で参照するオブジェクトに置換できます。 オブジェクトの格納場所は、参照パラメーターの値としてメソッドに渡されます。 パラメーターの格納場所の値を変更する場合は (新しいオブジェクトをポイント)、呼び出し元が参照する格納場所を変更することもできます。 次の例では、参照型のインスタンスを ref
パラメーターとして渡します。
class Product
{
public Product(string name, int newID)
{
ItemName = name;
ItemID = newID;
}
public string ItemName { get; set; }
public int ItemID { get; set; }
}
private static void ChangeByReference(ref Product itemRef)
{
// Change the address that is stored in the itemRef parameter.
itemRef = new Product("Stapler", 99999);
// You can change the value of one of the properties of
// itemRef. The change happens to item in Main as well.
itemRef.ItemID = 12345;
}
private static void ModifyProductsByReference()
{
// Declare an instance of Product and display its initial values.
Product item = new Product("Fasteners", 54321);
System.Console.WriteLine("Original values in Main. Name: {0}, ID: {1}\n",
item.ItemName, item.ItemID);
// Pass the product instance to ChangeByReference.
ChangeByReference(ref item);
System.Console.WriteLine("Back in Main. Name: {0}, ID: {1}\n",
item.ItemName, item.ItemID);
}
// This method displays the following output:
// Original values in Main. Name: Fasteners, ID: 54321
// Back in Main. Name: Stapler, ID: 12345
参照型を値渡しまたは参照渡しで渡す方法の詳細については、「参照型パラメーターの引き渡し」を参照してください。
参照戻り値
参照戻り値 (または ref 戻り値) は、メソッドから呼び出し元に参照渡しで返される値です。 つまり、呼び出し元はメソッドによって返される値を変更することができ、その変更は呼び出されたメソッド内のオブジェクトの状態に反映されます。
参照戻り値は ref
キーワードを使用して以下に定義されます。
- メソッド シグネチャ。 たとえば、次のメソッド シグネチャは、
GetCurrentPrice
メソッドが参照渡しで Decimal 値を返すことを示しています。
public ref decimal GetCurrentPrice()
- メソッドの
return
ステートメントで返される変数とreturn
トークンの間。 次に例を示します。
return ref DecimalArray[0];
呼び出し元がオブジェクトの状態を変更するには、参照戻り値を、参照変数として明示的に定義された変数に格納する必要があります。
次に、メソッド シグネチャとメソッド本体の両方を示す、より完全な ref 戻り値の例を示します。
public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
呼び出されるメソッドでは、値が参照渡しで値が返されるように戻り値を ref readonly
として宣言し、返された値を呼び出し元のコードで変更できないようにすることもできます。 呼び出し元のメソッドを使うと、ローカルの ref readonly
参照変数に値を格納することで、返された値のコピーを回避できます。
例については、「ref 戻り値と ref ローカル変数の使用例」を参照してください。
ref 戻り値と ref ローカル変数の使用例
次の例は、Title
と Author
という 2 つの String フィールドを持つ Book
クラスを定義しています。 また、Book
オブジェクトのプライベート配列を含む BookCollection
クラスも定義しています。 個々のブック オブジェクトは、GetBookByTitle
メソッドを呼び出すことによって参照渡しで返されます。
public class Book
{
public string Author;
public string Title;
}
public class BookCollection
{
private Book[] books = { new Book { Title = "Call of the Wild, The", Author = "Jack London" },
new Book { Title = "Tale of Two Cities, A", Author = "Charles Dickens" }
};
private Book nobook = null;
public ref Book GetBookByTitle(string title)
{
for (int ctr = 0; ctr < books.Length; ctr++)
{
if (title == books[ctr].Title)
return ref books[ctr];
}
return ref nobook;
}
public void ListBooks()
{
foreach (var book in books)
{
Console.WriteLine($"{book.Title}, by {book.Author}");
}
Console.WriteLine();
}
}
呼び出し元が GetBookByTitle
によって返される値を ref ローカル変数として格納する場合、呼び出し元が戻り値に加えた変更が BookCollection
オブジェクトに反映されます。次の例を参照してください。
var bc = new BookCollection();
bc.ListBooks();
ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
book = new Book { Title = "Republic, The", Author = "Plato" };
bc.ListBooks();
// The example displays the following output:
// Call of the Wild, The, by Jack London
// Tale of Two Cities, A, by Charles Dickens
//
// Republic, The, by Plato
// Tale of Two Cities, A, by Charles Dickens
C# 言語仕様
詳細については、「C# 言語の仕様」を参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。
関連項目
.NET feedback
The .NET documentation is open source. Provide feedback here.
フィードバック
フィードバックの送信と表示