선언문

선언문은 새 지역 변수, 지역 상수 또는 지역 참조 변수를 선언합니다. 지역 변수를 선언하려면 해당 형식을 지정하고 해당 이름을 제공합니다. 다음 예제와 같이 한 문에서 동일한 형식의 여러 변수를 선언할 수 있습니다.

string greeting;
int a, b, c;
List<double> xs;

선언문에서 초기 값을 사용하여 변수를 초기화할 수도 있습니다.

string greeting = "Hello";
int a = 3, b = 2, c = a + b;
List<double> xs = new();

앞의 예제에서는 변수의 형식을 명시적으로 지정합니다. 컴파일러가 초기화 식에서 변수 형식을 유추하도록 할 수도 있습니다. 이렇게 하려면 형식 이름 대신 var 키워드를 사용합니다. 자세한 내용은 암시적 형식 지역 변수 섹션을 참조하세요.

지역 상수를 선언하려면 다음 예제와 같이 const 키워드를 사용합니다.

const string Greeting = "Hello";
const double MinLimit = -10.0, MaxLimit = -MinLimit;

지역 상수도 선언할 때 초기화해야 합니다.

지역 참조 변수에 대한 자세한 내용은 참조 변수 섹션을 참조하세요.

암시적 형식 지역 변수

지역 변수를 선언할 때 컴파일러가 초기화 식에서 변수의 형식을 유추하도록 할 수 있습니다. 이렇게 하려면 형식 이름 대신 var 키워드를 사용합니다.

var greeting = "Hello";
Console.WriteLine(greeting.GetType());  // output: System.String

var a = 32;
Console.WriteLine(a.GetType());  // output: System.Int32

var xs = new List<double>();
Console.WriteLine(xs.GetType());  // output: System.Collections.Generic.List`1[System.Double]

앞의 예제에서 알 수 있듯이 암시적 형식 지역 변수는 강력한 형식입니다.

참고 항목

활성화된 null 허용 인식 컨텍스트에서 var을 사용하고 초기화 식의 형식이 참조 형식인 경우 초기화 식의 형식이 null을 허용하지 않는 경우에도 컴파일러는 항상 null 허용 참조 형식을 유추합니다.

var은 일반적으로 생성자 호출 식과 함께 사용됩니다. var를 사용하면 다음 예제와 같이 변수 선언 및 개체 인스턴스화에서 형식 이름을 반복하지 않을 수 있습니다.

var xs = new List<int>();

대상 형식 new을 대신 사용할 수 있습니다.

List<int> xs = new();
List<int>? ys = new();

무명 형식을 사용하는 경우 암시적 형식화 지역 변수를 사용해야 합니다. 다음 예제에서는 무명 형식을 사용하여 고객의 이름 및 전화번호를 보유하는 쿼리 식을 보여줍니다.

var fromPhoenix = from cust in customers
                  where cust.City == "Phoenix"
                  select new { cust.Name, cust.Phone };

foreach (var customer in fromPhoenix)
{
    Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
}

앞의 예제에서는 fromPhoenix 변수의 형식을 명시적으로 지정할 수 없습니다. 형식은 IEnumerable<T>이지만 이 경우 T는 무명 형식이므로 해당 이름을 제공할 수 없습니다. 이 때문에 var을 사용해야 합니다. 같은 이유로 foreach 문에서 customer 반복 변수를 선언할 때 var을 사용해야 합니다.

암시적 형식 지역 변수에 대한 자세한 내용은 암시적 형식 지역 변수를 참조하세요.

패턴 일치에서 var 키워드는 var 패턴에 사용됩니다.

참조 변수

지역 변수를 선언하고 변수의 형식 앞에 ref 키워드를 추가할 때 참조 변수 또는 ref 지역을 선언합니다.

ref int alias = ref variable;

참조 변수는 참조 대상(referent)이라고 하는 다른 변수를 참조하는 변수입니다. 즉, 참조 변수는 해당 참조 대상에 대한 별칭입니다. 참조 변수에 값을 할당하면 해당 값이 참조 대상에 할당됩니다. 참조 변수의 값을 읽으면 참조 대상의 값이 반환됩니다. 다음 예제에서는 해당 동작을 보여줍니다.

int a = 1;
ref int alias = ref a;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (1, 1)

a = 2;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (2, 2)

alias = 3;
Console.WriteLine($"(a, alias) is ({a}, {alias})");  // output: (a, alias) is (3, 3)

다음 예제와 같이 ref 대입 연산자= ref를 사용하여 참조 변수의 참조 대상을 변경합니다.

void Display(int[] s) => Console.WriteLine(string.Join(" ", s));

int[] xs = [0, 0, 0];
Display(xs);

ref int element = ref xs[0];
element = 1;
Display(xs);

element = ref xs[^1];
element = 3;
Display(xs);
// Output:
// 0 0 0
// 1 0 0
// 1 0 3

앞의 예제에서 element 참조 변수는 첫 번째 배열 요소에 대한 별칭으로 초기화됩니다. 그런 다음 마지막 배열 요소를 참조하도록 ref가 다시 할당됩니다.

ref readonly 지역 변수를 정의할 수 있습니다. ref readonly 변수에는 값을 할당할 수 없습니다. 그러나 다음 예제와 같이 이러한 참조 변수를 ref 재할당할 수 있습니다.

int[] xs = [1, 2, 3];

ref readonly int element = ref xs[0];
// element = 100;  error CS0131: The left-hand side of an assignment must be a variable, property or indexer
Console.WriteLine(element);  // output: 1

element = ref xs[^1];
Console.WriteLine(element);  // output: 3

다음 예제와 같이 참조 변수에 참조 반환을 할당할 수 있습니다.

using System;

public class NumberStore
{
    private readonly int[] numbers = [1, 30, 7, 1557, 381, 63, 1027, 2550, 511, 1023];

    public ref int GetReferenceToMax()
    {
        ref int max = ref numbers[0];
        for (int i = 1; i < numbers.Length; i++)
        {
            if (numbers[i] > max)
            {
                max = ref numbers[i];
            }
        }
        return ref max;
    }

    public override string ToString() => string.Join(" ", numbers);
}

public static class ReferenceReturnExample
{
    public static void Run()
    {
        var store = new NumberStore();
        Console.WriteLine($"Original sequence: {store.ToString()}");
        
        ref int max = ref store.GetReferenceToMax();
        max = 0;
        Console.WriteLine($"Updated sequence:  {store.ToString()}");
        // Output:
        // Original sequence: 1 30 7 1557 381 63 1027 2550 511 1023
        // Updated sequence:  1 30 7 1557 381 63 1027 0 511 1023
    }
}

앞의 예제에서 GetReferenceToMax 메서드는 참조로 반환(return-by-ref) 메서드입니다. 최대값 자체는 반환하지 않지만 최대값을 보유하는 배열 요소에 대한 별칭인 참조 반환입니다. Run 메서드는 max 참조 변수에 참조 반환을 할당합니다. 그런 다음 max에 할당하여 store 인스턴스의 내부 스토리지를 업데이트합니다. ref readonly 메서드를 정의할 수도 있습니다. ref readonly 메서드의 호출자는 해당 참조 반환에 값을 할당할 수 없습니다.

foreach 문의 반복 변수는 참조 변수일 수 있습니다. 자세한 내용은 반복 문 문서의 foreach 섹션을 참조하세요.

성능이 중요한 시나리오에서 참조 변수 및 반환을 사용하면 잠재적으로 비용이 많이 들 수 있는 복사 작업을 방지하여 성능이 좋아질 수 있습니다.

컴파일러는 참조 변수가 참조 대상보다 오래 유지되지 않고 전체 수명 동안 유효한 상태를 유지하도록 합니다. 자세한 내용은 C# 언어 사양ref 안전 컨텍스트 섹션을 참조하세요.

ref 필드에 대한 자세한 내용은 ref 구조체 형식 문서의 ref 필드 섹션을 참조하세요.

scoped ref

상황별 키워드 scoped는 값의 수명을 제한합니다. scoped 한정자는 ref-safe-to-escape 또는 safe-to-escape 수명을 각각 현재 메서드로 제한합니다. 실질적으로 scoped 한정자 추가는 코드가 변수의 수명을 연장하지 않는다는 어설션입니다.

scoped는 매개 변수 또는 지역 변수에 적용할 수 있습니다. 형식이 ref struct인 경우 매개 변수 및 지역 변수에 scoped 한정자를 적용할 수 있습니다. 그렇지 않으면 scoped 한정자는 지역 참조 변수에만 적용될 수 있습니다. 여기에는 ref 한정자를 사용하여 선언된 지역 변수와 in, ref 또는 out 한정자를 사용하여 선언된 매개 변수가 포함됩니다.

scoped 한정자는 형식이 ref struct인 경우 struct에 선언된 메서드의 this, out 매개 변수 및 ref 매개 변수에 암시적으로 추가됩니다.

C# 언어 사양

자세한 내용은 C# 언어 사양의 다음 섹션을 참조하세요.

scoped 한정자에 대한 자세한 내용은 하위 수준 구조체 개선 제안 참고 사항을 참조하세요.

참고 항목