대입 연산자
대입 연산자 (C# 참조)
우리가 값을 변수에 넣을 때 쓰는 = 연산자부터, 참조를 다시 꽂는 = ref, 그리고 더 짧게 쓰는 복합 대입까지 정리해 볼게요. C# 대입 연산자가 다루는 범위가 꽤 넓어서, 하나씩 짚어 가며 어떤 상황에 어떤 걸 쓰는지 보시면 좋아요.
본문
기본 대입 =
대입 연산자 =는 오른쪽 피연산자의 값(value) 을 왼쪽 피연산자가 가리키는 대상, 즉 속성(property)이나 인덱서(indexer) 요소에 할당해요. 이때 대입 표현식의 결과는 왼쪽 피연산자에 할당된 값 그 자체예요. 그리고 오른쪽 피연산자의 타입은 왼쪽 피연산자의 타입과 같거나, 그 타입으로 암시적으로 변환될 수 있어야 해요.
대입 연산자 =는 오른쪽 결합(right-associative) 이라서 아래처럼 쓰면
a = b = c
실제로는 이렇게 계산돼요.
a = (b = c)
즉 오른쪽의 b = c가 먼저 처리되고, 그 결과가 a에 들어가는 거죠.
대입 연산자를 지역 변수, 속성, 인덱서 요소를 왼쪽 피연산자로 해서 쓰는 실제 예시는 아래 코드에서 확인할 수 있어요.
// 예시: 지역 변수, 속성, 인덱서 요소에 값을 대입하는 모습
// (원문 snippet: AssignmentOperator.cs의 SnippetSimple 참고)
대입의 왼쪽 피연산자는 오른쪽 피연산자의 값을 받아요. 피연산자가 값 타입(value types)이면 대입은 오른쪽 피연산자의 내용을 복사하고, 참조 타입(reference types)이면 객체에 대한 참조를 복사해요. 이걸 값 대입(value assignment) 이라고 불러요 — 값 자체가 할당되는 연산이라는 뜻이에요.
C# 14부터 값 대입의 왼쪽에는 ?.이나 ?[] 같은 null 조건부 멤버 표현식도 올 수 있어요. 이때 왼쪽이 null이면 오른쪽 표현식은 아예 평가되지 않아요.
ref 대입 = ref
ref 대입 = ref는 왼쪽 피연산자를 오른쪽 피연산자의 별칭(alias) 으로 만들어요. 아래 예시를 볼게요.
// 예시: 로컬 참조 변수를 배열 요소의 별칭으로 만들고 다시 ref 대입
// (원문 snippet: AssignmentOperator.cs의 SnippetRefAssignment 참고)
위 예시에서 로컬 참조 변수 arrayElement는 배열의 첫 요소에 대한 별칭으로 초기화돼요. 그다음 ref 대입으로 배열의 마지막 요소를 가리키도록 다시 꽂죠. 별칭이기 때문에, 평범한 대입 연산자 =로 그 값을 바꾸면 해당 배열 요소도 함께 갱신돼요.
ref 대입의 왼쪽 피연산자가 될 수 있는 건 로컬 참조 변수, ref 필드, 그리고 ref, out, in 메서드 매개변수예요. 이때 두 피연산자는 반드시 같은 타입이어야 해요.
ref 대입의 핵심은 참조 변수가 가리키는 대상(referent)이 바뀐다는 거예요. 이전에 가리키던 대상을 더 이상 가리키지 않게 되죠. ref 매개변수에 = ref를 쓰면 그 매개변수는 더 이상 원래 인자를 가리키지 않아요. 그리고 ref 대입 이후에 객체의 상태를 바꾸는 모든 동작은 새로운 대상에 적용돼요. 다음 메서드를 볼게요.
// 예시: ref 재대입 후 객체 상태를 수정하는 메서드
// (원문 snippet: AssignmentOperator.cs의 SnippetRefReassignAndModify 참고)
아래 사용 예시를 보면, 매개변수 s는 문자열이 수정되기 전에 sLocal을 가리키도록 ref 재대입되었기 때문에, 메서드 호출 이후에는 s에 한 대입이 밖에서 전혀 보이지 않아요.
// 예시: 메서드 호출 후 대입 결과가 보이지 않는 모습
// (원문 snippet: AssignmentOperator.cs의 Usage 참고)
복합 대입 (Compound assignment)
이항 연산자 op에 대해 복합 대입 표현식은 꼴이
x op= y
이렇게 생겼고, 이건 아래와 같아요.
x = x op y
단, 유일한 차이가 있는데 x가 한 번만 평가된다는 거예요.
산술, 부울 논리, 그리고 비트 논리와 시프트 연산자들이 모두 복합 대입을 지원해요.
null 병합 대입 ??=
null 병합 대입 연산자 ??=는 왼쪽 피연산자가 null로 평가될 경우에만 오른쪽 피연산자의 값을 왼쪽으로 대입해요. 더 자세한 내용은 ??와 ??= 연산자 문서를 참고하세요.
연산자 오버로드 가능 여부
사용자 정의 타입은 대입 연산자를 오버로드할 수 없어요. 다만 사용자 정의 타입이 다른 타입으로의 암시적 변환을 정의하면, 이 변환을 이용해 그 타입의 값을 다른 타입의 변수·속성·인덱서 요소에 대입할 수 있어요. 자세한 내용은 사용자 정의 변환 연산자를 보세요.
사용자 정의 타입이 이항 연산자 op를 오버로드하면, op= 연산자(있을 경우)도 암시적으로 함께 오버로드돼요. C# 14부터는 사용자 정의 타입이 복합 대입 연산자 op=를 명시적으로 오버로드해서 더 효율적인 구현을 제공할 수도 있어요. 보통 타입이 이 연산자를 오버로드하는 이유는, 이항 연산의 결과를 담을 새 인스턴스를 할당하는 대신 값을 그 자리에서(in place) 갱신할 수 있기 때문이에요. 타입이 명시적 오버로드를 제공하지 않으면 컴파일러가 암시적 오버로드를 생성해요.
C# 언어 사양
더 자세한 내용은 C# 언어 사양의 대입 연산자 섹션과 사용자 정의 복합 대입 기능 사양을 참고하세요.