연산자 오버로딩 — 미리 정의된 단항·산술·같음·비교 연산자
연산자 오버로딩 — 미리 정의된 단항·산술·같음·비교 연산자
C#의 미리 정의된 연산자는 사용자 정의 형식에서 오버로딩할 수 있어요. 연산자를 오버로딩하면, 그 연산자를 쓰는 두 피연산자 중 하나(또는 둘 다)가 해당 형식일 때 실행될 나만의 구현을 제공하는 셈이죠. 오버로딩할 수 있는 C# 연산자 목록은 오버로딩 가능한 연산자 섹션에서 확인할 수 있어요.
출처: Operator overloading - predefined unary, arithmetic, equality, and comparison operators
연산자를 선언할 때는 operator 키워드를 써요. 연산자 선언은 다음 규칙을 따라야 합니다.
public한정자를 포함해야 해요.- 단항 연산자는 입력 매개 변수를 하나, 이항 연산자는 입력 매개 변수를 두 개 가져요. 어느 경우든 매개 변수 중 적어도 하나는
T또는T?형식이어야 하는데, 여기서T는 그 연산자 선언이 들어 있는 형식을 뜻해요. +=같은 복합 할당 연산자를 제외하고는static한정자를 포함해야 해요.- 증가(
++)와 감소(--) 연산자는 static 메서드나 인스턴스 메서드 중 하나로 구현할 수 있어요. 인스턴스 메서드 연산자는 C# 14에서 새로 도입된 기능이에요.
본문
아래 예시는 유리수를 표현하는 단순한 구조체를 정의한 건데요, 산술 연산자 일부를 오버로딩하고 있어요.
// OperatorOverloading.cs 코드
이 예시는 암시적 변환을 정의해서 int를 Fraction으로 바꾸도록 확장할 수도 있어요. 그러면 오버로딩된 연산자가 그 두 형식의 인자를 지원하게 되죠. 즉, 정수와 유리수를 더해서 결과로 유리수를 얻는 일이 가능해지는 거예요.
operator 키워드는 사용자 정의 형식 변환을 정의할 때도 써요. 자세한 내용은 사용자 정의 변환 연산자에서 다뤄요.
오버로딩 가능한 연산자
다음 표는 오버로딩할 수 있는 연산자들을 보여줍니다.
| 연산자 | 참고 |
|---|---|
+x, -x, !x, ~x, ++, --, true, false |
true와 false 연산자는 반드시 함께 오버로딩해야 해요. |
x + y, x - y, x * y, x / y, x % y, x & y, x | y, x ^ y, x << y, x >> y, x >>> y |
|
x == y, x != y, x < y, x > y, x <= y, x >= y |
다음처럼 반드시 쌍으로 오버로딩해야 해요: ==와 !=, <와 >, <=와 >=. |
+=, -=, *=, /=, %=, &=, [` |
=](boolean-logical-operators.md#compound-assignment), [^=](boolean-logical-operators.md#compound-assignment), [<<=](bitwise-and-shift-operators.md#compound-assignment), [>>=](bitwise-and-shift-operators.md#compound-assignment), [>>>=`](bitwise-and-shift-operators.md#compound-assignment) |
복합 할당 연산자를 오버로딩할 때는 다음 규칙을 지켜야 해요.
public한정자를 포함해야 해요.static한정자는 포함할 수 없어요.- 반환 형식은
void여야 해요. - 선언에는 복합 할당의 오른쪽 피연산자를 나타내는 매개 변수 하나를 포함해야 해요.
C# 14부터는 증가(++)와 감소(--) 연산자를 인스턴스 멤버로 오버로딩할 수 있어요. 인스턴스 연산자는 새 인스턴스 생성을 피해 성능을 높일 수 있는데요, 다음 규칙을 따라야 해요.
public한정자를 포함해야 해요.static한정자는 포함할 수 없어요.- 반환 형식은
void여야 해요. - 매개 변수는 하나도 선언할 수 없어요. 설령 기본값이 있는 매개 변수라도 마찬가지예요.
오버로딩할 수 없는 연산자
다음 표는 오버로딩할 수 없는 연산자들을 보여줍니다.
| 연산자 | 대안 |
|---|---|
x && y, x || y |
true와 false 연산자, 그리고 & 또는 | 연산자를 모두 오버로딩하면 돼요. 자세한 내용은 사용자 정의 조건 논리 연산자를 참고하세요. |
a[i], a?[i] |
인덱서를 정의하면 돼요. |
(T)x |
캐스트 식이 수행하는 사용자 정의 형식 변환을 정의하면 돼요. 자세한 내용은 사용자 정의 변환 연산자를 참고하세요. |
^x, x = y, x.y, x?.y, c ? t : f, x ?? y, ??= y,x..y, x->y, =>, f(x), as, await, checked, unchecked, default, delegate, is, nameof, new, sizeof, stackalloc, switch, typeof, with |
없음. |
C# 14 이전에는 복합 연산자를 오버로딩할 수 없어요. 대신 대응하는 이항 연산자를 오버로딩하면 그 복합 할당 연산자가 암시적으로 함께 오버로딩되는 방식이었죠.
연산자 오버로딩 해석
[!IMPORTANT] 이 섹션은 C# 14 이상에 적용돼요. C# 14 이전에는 사용자 정의 복합 할당 연산자와 인스턴스 증가·감소 연산자를 사용할 수 없었어요.
x «op»= y 같은 복합 할당 식에서 x가 변수로 분류되면, 인스턴스 연산자가 «op»의 static 연산자보다 우선해요. 반대로 x의 형식이 오버로딩된 «op»= 연산자를 선언하지 않았거나, x가 변수로 분류되지 않으면 static 연산자가 사용돼요.
후치 연산자 ++의 경우, x가 변수로 분류되지 않거나 x++ 식이 쓰였다면 인스턴스 operator++는 무시돼요. 그 외에는 인스턴스 operator ++가 우선됩니다. 예를 들어,
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
이 규칙이 있는 이유는 y에는 증가시키기 전의 x 값을 할당해야 하기 때문이에요. 참조 형식의 사용자 정의 구현에서는 컴파일러가 그 값을 확정할 수 없거든요.
전치 연산자 ++의 경우, ++x에서 x가 변수로 분류되면 인스턴스 연산자가 static 단항 연산자보다 우선해요.