ref(C# 참조)ref (C# Reference)

ref 키워드는 참조로 전달되는 값을 나타냅니다.The ref keyword indicates a value that is passed by reference. 다음 네 가지 컨텍스트에서 사용됩니다.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.
  • ref struct 또는 readonly ref struct을 선언하기 위한 struct 선언서.In a struct declaration to declare a ref struct or a readonly ref struct. 자세한 내용은 ref struct 형식을 참조하세요.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. 이 두 개념은 서로 다릅니다.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. 참조로 전달되는 경우 값 형식은 boxing되지 않습니다.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);
Console.WriteLine(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.

클래스의 멤버는 ref, in 또는 out만 다른 서명을 포함할 수 없습니다.Members of a class can't have signatures that differ only by ref, in, or out. 특정 형식의 두 멤버가 하나는 ref 매개 변수를 포함하고 다른 하나는 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) { }
}

그러나 다음 예제에 나와 있는 것처럼 메서드 하나에는 ref, in 또는 out 매개 변수가 포함되어 있고 다른 하나에는 값 매개 변수가 포함되어 있으면 메서드를 오버로드할 수 있습니다.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) { }
}

숨기기나 재정의와 같이 서명이 일치해야 하는 다른 상황에서는 in, refout이 서명의 일부가 되며 서로 일치하지 않습니다.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.

다음과 같은 종류의 메서드에는 ref, inout 키워드를 사용할 수 없습니다.You can't use the ref, in, and out keywords for the following kinds of methods:

  • async 한정자를 사용하여 정의하는 비동기 메서드Async methods, which you define by using the async modifier.
  • yield return 또는 yield break 문을 포함하는 반복기 메서드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 return)은 메서드가 호출자에게 참조로 반환하는 값입니다.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];

호출자가 개체 상태를 수정하려면 참조 반환 값을 참조 로컬로 명시적으로 정의된 변수에 저장해야 합니다.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 locals

참조 지역 변수는 return ref을 사용하여 반환된 값을 참조하는 데 사용됩니다.A ref local variable is used to refer to values returned using return 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. 참조 로컬 값의 수정 내용은 메서드가 값을 참조로 반환하는 개체 상태에 반영됩니다.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 키워드를 사용하여 참조 로컬을 정의합니다.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 메서드에서 반환되는 참조 로컬 값을 정의합니다.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. 예를 들어, 다음 명령문은 값을 참조하는 데 사용되는 참조 로컬 값을 정의하는 방법을 보여줍니다.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.

참조 반환 및 참조 로컬 예제A ref returns and ref locals example

다음 예제에서는 두 개의 String 필드 TitleAuthor가 있는 Book 클래스를 정의합니다.The following example defines a Book class that has two String fields, Title and Author. 또한 Book 개체의 private 배열을 포함하는 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}");
        }
        Console.WriteLine();
    }
}

호출자가 GetBookByTitle 메서드에서 참조 로컬로 반환된 값을 저장하는 경우 호출자가 반환 값을 변경하면 다음 예제와 같이 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();
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

Ref struct 형식Ref struct types

struct 선언에 ref 한정자를 추가하면 해당 형식의 인스턴스가 스택에 할당되도록 정의합니다.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를 boxing할 수 없습니다.You can't box a ref struct. ref struct 형식을 object, dynamic 형식 또는 인터페이스 유형의 변수에 할당할 수 없습니다.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 field member of a class or a normal struct. 여기에는 컴파일러에서 생성된 지원 필드를 만드는 자동 구현 속성의 선언이 포함됩니다.This includes declaring an auto-implemented property, which creates a compiler generated backing field.
  • 비동기 메서드에 ref struct 형식인 로컬 변수를 선언할 수 없습니다.You cannot declare local variables that are ref struct types in async methods. Task, Task<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 structref structreadonly 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# 언어 사양은 C# 구문 및 사용법에 대한 신뢰할 수 있는 소스입니다.The language specification is the definitive source for C# syntax and usage.

참고 항목See also