ref (C# リファレンス)ref (C# Reference)

ref キーワードは、参照渡しで渡される値を示します。The ref keyword indicates a value that is passed by reference. このキーワードは、4 つの異なるコンテキストで使用されます。It is used in four different contexts:

  • メソッド シグネチャとメソッドの呼び出しで、参照によってメソッドに引数を渡します。In a method signature and in a method call, to pass an argument to a method by reference. 詳細については、「参照渡しで引数を渡す」を参照してください。For more information, see Passing an argument by reference.
  • メソッド シグネチャで、参照渡しで呼び出し元に値を返します。In a method signature, to return a value to the caller by reference. 詳細については、参照戻り値に関するページを参照してください。For more information, see Reference return values.
  • メンバーの本文で、参照戻り値が、呼び出し元によって変更される参照としてローカルに格納されること、または、通常はローカル変数が参照渡しによって別の値にアクセスすることを示します。In a member body, to indicate that a reference return value is stored locally as a reference that the caller intends to modify or, in general, a local variable accesses another value by reference. 詳細については、「ref ローカル変数」を参照してください。For more information, see Ref locals.
  • struct の宣言で、ref struct または ref readonly struct を宣言します。In a struct declaration to declare a ref struct or a ref readonly struct. 詳細については、「ref 構造体型」を参照してください。For more information, see ref struct types.

参照渡しで引数を渡すPassing an argument by reference

メソッドのパラメーター リストで使用した場合、ref キーワードは、引数を値ではなく、参照によって渡すことを示します。When used in a method's parameter list, the ref keyword indicates that an argument is passed by reference, not by value. ref キーワードは、仮パラメーターを引数 (変数にする必要があります) の別名にします。The ref keyword makes the formal parameter an alias for the argument, which must be a variable. つまり、パラメーターに対するすべての操作は引数に対して行われます。In other words, any operation on the parameter is made on the argument. たとえば、呼び出し元がローカル変数の式、または配列要素のアクセス式を渡し、呼び出されたメソッドが ref パラメーターが参照するオブジェクトを置き換える場合、メソッドが戻ったときに呼び出し元のローカル変数または配列要素は新しいオブジェクトを参照します。For example, if the caller passes a local variable expression or an array element access expression, and the called method replaces the object to which the ref parameter refers, then the caller’s local variable or the array element now refers to the new object when the method returns.


参照渡しの概念と参照型の概念を混同しないでください。Do not confuse the concept of passing by reference with the concept of reference types. 2 つの概念は同じではありません。The two concepts are not the same. メソッドのパラメーターは、値型か参照型かどうかに関係なく、ref によって変更できます。A method parameter can be modified by ref regardless of whether it is a value type or a reference type. 参照渡しで渡される場合、値型はボックス化されません。There is no boxing of a value type when it is passed by reference.

ref パラメーターを使用するには、メソッド定義と呼び出し元のメソッドの両方が、次の例に示すように ref キーワードを明示的に使用する必要があります。To use a ref parameter, both the method definition and the calling method must explicitly use the ref keyword, as shown in the following example.

void Method(ref int refArgument)
    refArgument = refArgument + 44;

int number = 1;
Method(ref number);
// Output: 45

ref または in パラメーターに渡す引数は、渡す前に初期化する必要があります。An argument that is passed to a ref or in parameter must be initialized before it is passed. これは、引数を渡す前に明示的に初期化する必要がない out パラメーターとは異なります。This differs from out parameters, whose arguments do not have to be explicitly initialized before they are passed.

クラスのメンバーは、refin、または out のみが異なるシグネチャを持つことはできません。Members of a class can't have signatures that differ only by ref, in, or out. 1 つの型の 2 つのメンバー間の唯一の違いが、1 つには ref パラメーターが存在し、もう 1 つには out または in パラメーターが存在することである場合、コンパイラ エラーが発生します。A compiler error occurs if the only difference between two members of a type is that one of them has a ref parameter and the other has an out, or in parameter. たとえば、次のコードはコンパイルされません。The following code, for example, doesn't compile.

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 つのメソッドに refin または out パラメーターがあり、もう 1 つのメソッドに値パラメーターがある場合、メソッドをオーバーロードすることができます。However, methods can be overloaded when one method has a ref, in, or out parameter and the other has a value parameter, as shown in the following example.

class RefOverloadExample
    public void SampleMethod(int i) { }
    public void SampleMethod(ref int i) { }

非表示やオーバーライドなど、シグネチャの一致が必要な他の状況では、inrefout はシグネチャの一部であり、互いに一致しません。In other situations that require signature matching, such as hiding or overriding, in, ref, and out are part of the signature and don't match each other.

プロパティは変数ではありません。Properties are not variables. プロパティはメソッドであり、ref パラメーターに渡すことはできません。They are methods, and cannot be passed to ref parameters.

次の種類のメソッドには、refinout キーワードを使用することはできません。You can't use the ref, in, and out keywords for the following kinds of methods:

  • async 修飾子を使用して定義した Async メソッド。Async methods, which you define by using the async modifier.
  • yield return または yield break ステートメントを含む Iterator メソッド。Iterator methods, which include a yield return or yield break statement.

参照渡しで引数を渡す:使用例Passing an argument by reference: An example

前の例は、参照によって値型を渡す例でした。The previous examples pass value types by reference. ref キーワードを使用して、参照渡しで参照型を渡すこともできます。You can also use the ref keyword to pass reference types by reference. 参照型を参照渡しで渡すと、呼び出されたメソッドは、参照パラメーターが呼び出し元で参照するオブジェクトに置換できます。Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller. オブジェクトの格納場所は、参照パラメーターの値としてメソッドに渡されます。The storage location of the object is passed to the method as the value of the reference parameter. パラメーターの格納場所の値を変更する場合は (新しいオブジェクトをポイント)、呼び出し元が参照する格納場所を変更することもできます。If you change the value in the storage location of the parameter (to point to a new object), you also change the storage location to which the caller refers. 次の例では、参照型のインスタンスを ref パラメーターとして渡します。The following example passes an instance of a reference type as a ref parameter.

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        

参照型を値渡しまたは参照渡しで渡す方法の詳細については、「参照型パラメーターの引き渡し」を参照してください。For more information about how to pass reference types by value and by reference, see Passing Reference-Type Parameters.

参照戻り値Reference return values

参照戻り値 (または ref 戻り値) は、メソッドから呼び出し元に参照渡しで返される値です。Reference return values (or ref returns) are values that a method returns by reference to the caller. つまり、呼び出し元はメソッドによって返される値を変更することができ、メソッドを格納するオブジェクトの状態にその変更が反映されます。That is, the caller can modify the value returned by a method, and that change is reflected in the state of the object that contains the method.

参照戻り値は ref キーワードを使用して以下に定義されます。A reference return value is defined by using the ref keyword:

  • メソッド シグネチャ。In the method signature. たとえば、次のメソッド シグネチャは、GetCurrentPrice メソッドが参照渡しで Decimal 値を返すことを示しています。For example, the following method signature indicates that the GetCurrentPrice method returns a Decimal value by reference.
public ref decimal GetCurrentPrice()
  • メソッドの return ステートメントで返される変数と return トークンの間。Between the return token and the variable returned in a return statement in the method. 次に例を示します。For example:
return ref DecimalArray[0];

呼び出し元がオブジェクトの状態を変更するには、ref ローカル変数として明示的に定義した変数に参照戻り値を格納する必要があります。In order for the caller to modify the object's state, the reference return value must be stored to a variable that is explicitly defined as a ref local.

呼び出されたメソッドによって、戻り値が ref readonly として宣言されて参照渡しで値が返されることもあり、返された値が呼び出し元のコードで変更できないように強制されることもあります。The called method may also declare the return value as ref readonly to return the value by reference, and enforce that the calling code cannot modify the returned value. 呼び出し元のメソッドでは、ローカルの ref readonly 変数に値を格納することで、返された値のコピーを回避できます。The calling method can avoid copying the returned valued by storing the value in a local ref readonly variable.

例については、「ref 戻り値と ref ローカル変数の使用例」を参照してください。For an example, see A ref returns and ref locals example.

ref ローカル変数Ref locals

ref ローカル変数は、return ref を使用して返された値を参照するために使用します。A ref local variable is used to refer to values returned using return ref. ref ローカル変数は、初期化して ref 戻り値以外の値にすることができません。A ref local variable cannot be initialized to a non-ref return value. 言い換えると、初期化の右側は参照にする必要があります。In other words, the right hand side of the initialization must be a reference. ref ローカル変数の値に変更を加えると、参照渡しの値を返すメソッドのオブジェクトの状態に反映されます。Any modifications to the value of the ref local are reflected in the state of the object whose method returned the value by reference.

ref ローカル変数を定義するには、変数宣言の前と、参照渡しで値を返すメソッドの呼び出しの直前に、ref キーワードを使用します。You define a ref local by using the ref keyword before the variable declaration, as well as immediately before the call to the method that returns the value by reference.

たとえば、次のステートメントは、GetEstimatedValue という名前のメソッドによって返される ref ローカル変数を定義しています。For example, the following statement defines a ref local value that is returned by a method named GetEstimatedValue:

ref decimal estValue = ref Building.GetEstimatedValue();

同じ方法で、参照渡しの値にアクセスできます。You can access a value by reference in the same way. 場合によっては、参照渡しの値へのアクセスによって負荷がかかる可能性があるコピー操作が回避され、パフォーマンスが向上します。In some cases, accessing a value by reference increases performance by avoiding a potentially expensive copy operation. たとえば、次のステートメントは、値の参照に使用される ref ローカル値をどのように定義できるかを示しています。For example, the following statement shows how one can define a ref local value that is used to reference a value.

ref VeryLargeStruct reflocal = ref veryLargeStruct;

どちらの例も、ref キーワードは両方の位置で使用する必要があります。そうしないと、コンパイラ エラー CS8172 "値を使用して参照渡し変数を初期化することはできません" が生成されます。Note that in both examples the ref keyword must be used in both places, or the compiler generates error CS8172, "Cannot initialize a by-reference variable with a value."

C#7.3 以降、foreach ステートメントの反復変数を ref ローカルまたは ref readonly ローカル変数にすることができます。Beginning with C# 7.3, the iteration variable of the foreach statement can be ref local or ref readonly local variable. 詳細については、foreach ステートメントに関する記事を参照してください。For more information, see the foreach statement article.

ref readonly ローカルRef readonly locals

ref readonly ローカルは、その署名に ref readonly があり、return ref を使用するメソッドまたはプロパティにより返される値の参照に使用されます。A ref readonly local is used to refer to values returned by the method or property that has ref readonly in its signature and uses return ref. ref readonly 変数は ref ローカル変数のプロパティと readonly 変数の組み合わせです。それに割り当てられたストレージのエイリアスであり、変更できません。A ref readonly variable combines the properties of a ref local variable with a readonly variable: it is an alias to the storage it's assigned to, and it cannot be modified.

ref 戻り値と ref ローカル変数の使用例A ref returns and ref locals example

次の例は、TitleAuthor という 2 つの String フィールドを持つ Book クラスを定義しています。The following example defines a Book class that has two String fields, Title and Author. また、Book オブジェクトのプライベート配列を含む BookCollection クラスも定義しています。It also defines a BookCollection class that includes a private array of Book objects. 個々のブック オブジェクトは、GetBookByTitle メソッドを呼び出すことによって参照渡しで返されます。Individual book objects are returned by reference by calling its GetBookByTitle method.

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}");

呼び出し元が GetBookByTitle によって返される値を ref ローカル変数として格納する場合、呼び出し元が戻り値に加えた変更が BookCollection オブジェクトに反映されます。次の例を参照してください。When the caller stores the value returned by the GetBookByTitle method as a ref local, changes that the caller makes to the return value are reflected in the BookCollection object, as the following example shows.

var bc = new BookCollection();

ref var book = ref bc.GetBookByTitle("Call of the Wild, The");
if (book != null)
    book = new Book { Title = "Republic, The", Author = "Plato" };
// 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

ref 構造体型Ref struct types

ref 修飾子を struct 宣言に追加すると、その型のインスタンスにはスタック割り当てが必須になるように定義されます。Adding the ref modifier to a struct declaration defines that instances of that type must be stack allocated. 言い換えると、そのような型のインスタンスを別のクラスのメンバーとしてヒープ上で作成することはできません。In other words, instances of these types can never be created on the heap as a member of another class. この機能の第一の動機は Span<T> と関連構造でした。The primary motivation for this feature was Span<T> and related structures.

スタック割り当て変数として ref struct 型を維持する目的の下、すべての ref struct 型にコンパイラが適用する規則がいくつか導入されます。The goal of keeping a ref struct type as a stack-allocated variable introduces several rules that the compiler enforces for all ref struct types.

  • ref struct はボックス化できません。You can't box a ref struct. object 型、dynamic 型、またはあらゆるインターフェイス型の変数には、ref struct 型を割り当てることができません。You cannot assign a ref struct type to a variable of type object, dynamic, or any interface type.
  • ref struct 型では、インターフェイスを実装できません。ref struct types cannot implement interfaces.
  • クラスまたは通常構造体のメンバーとして ref struct を宣言することはできません。You can't declare a ref struct as a member of a class or a normal struct.
  • 非同期メソッドでは、ref struct 型のローカル変数を宣言できません。You cannot declare local variables that are ref struct types in async methods. TaskTask<TResult>Task のような型を返す同期メソッドで宣言できます。You can declare them in synchronous methods that return Task, Task<TResult> or Task-like types.
  • 反復子で ref struct ローカル変数を宣言することはできません。You cannot declare ref struct local variables in iterators.
  • ラムダ式またはローカル関数で ref struct 変数をキャプチャすることはできません。You cannot capture ref struct variables in lambda expressions or local functions.

これらの制約によって、誤って、マネージド ヒープに昇格させるような方法で ref struct を使用することが確実になくなります。These restrictions ensure you don't accidentally use a ref struct in a manner that could promote it to the managed heap.

修飾子を組み合わせ、構造体を readonly ref として宣言できます。You can combine modifiers to declare a struct as readonly ref. readonly ref struct では、ref struct 宣言と readonly struct 宣言の利点と制限が組み合わされます。A readonly ref struct combines the benefits and restrictions of ref struct and readonly struct declarations.

C# 言語仕様C# language specification

詳細については、「C# 言語の仕様」を参照してください。For more information, see the C# Language Specification. 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。The language specification is the definitive source for C# syntax and usage.

関連項目See also