사용자 정의 형식은 미리 정의된 C# 연산자를 오버로드할 수 있습니다. 즉, 피연산자 중 하나 또는 둘 다 해당 형식인 경우 형식은 작업의 사용자 지정 구현을 제공할 수 있습니다. 오버로드 가능한 연산자 섹션에는 오버로드할 수 있는 C# 연산자가 표시됩니다.
키워드를 operator
사용하여 연산자를 선언합니다. 연산자 선언은 다음 규칙을 충족해야 합니다.
- 여기에는 한정자가
public
포함됩니다. - 단항 연산자에는 하나의 입력 매개 변수가 있습니다. 이진 연산자에는 두 개의 입력 매개 변수가 있습니다. 각 경우에 하나 이상의 매개 변수는 형식
T
또는T?
이어야 하고, 연산자 선언이 포함된 형식은T
입니다. - 한정자가 포함됩니다
static
, 복합 할당 연산자와 같은+=
를 제외하고. - 증가(
++
) 및 감소(--
) 연산자는 정적 또는 인스턴스 메서드로 구현할 수 있습니다.
다음 예제에서는 합리적인 숫자를 나타내는 간소화된 구조를 정의합니다. 구조체가 일부 산술 연산자를 오버로드합니다.
public struct Fraction
{
private int numerator;
private int denominator;
public Fraction(int numerator, int denominator)
{
if (denominator == 0)
{
throw new ArgumentException("Denominator cannot be zero.", nameof(denominator));
}
this.numerator = numerator;
this.denominator = denominator;
}
public static Fraction operator +(Fraction operand) => operand;
public static Fraction operator -(Fraction operand) => new Fraction(-operand.numerator, operand.denominator);
public static Fraction operator +(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.denominator + right.numerator * left.denominator, left.denominator * right.denominator);
public static Fraction operator -(Fraction left, Fraction right)
=> left + (-right);
public static Fraction operator *(Fraction left, Fraction right)
=> new Fraction(left.numerator * right.numerator, left.denominator * right.denominator);
public static Fraction operator /(Fraction left, Fraction right)
{
if (right.numerator == 0)
{
throw new DivideByZeroException();
}
return new Fraction(left.numerator * right.denominator, left.denominator * right.numerator);
}
// Define increment and decrement to add 1/den, rather than 1/1.
public static Fraction operator ++(Fraction operand)
=> new Fraction(operand.numerator++, operand.denominator);
public static Fraction operator --(Fraction operand) =>
new Fraction(operand.numerator--, operand.denominator);
public override string ToString() => $"{numerator} / {denominator}";
// New operators allowed in C# 14:
public void operator +=(Fraction operand) =>
(numerator, denominator ) =
(
numerator * operand.denominator + operand.numerator * denominator,
denominator * operand.denominator
);
public void operator -=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.denominator - operand.numerator * denominator,
denominator * operand.denominator
);
public void operator *=(Fraction operand) =>
(numerator, denominator) =
(
numerator * operand.numerator,
denominator * operand.denominator
);
public void operator /=(Fraction operand)
{
if (operand.numerator == 0)
{
throw new DivideByZeroException();
}
(numerator, denominator) =
(
numerator * operand.denominator,
denominator * operand.numerator
);
}
public void operator ++() => numerator++;
public void operator --() => numerator--;
}
public static class OperatorOverloading
{
public static void Main()
{
var a = new Fraction(5, 4);
var b = new Fraction(1, 2);
Console.WriteLine(-a); // output: -5 / 4
Console.WriteLine(a + b); // output: 14 / 8
Console.WriteLine(a - b); // output: 6 / 8
Console.WriteLine(a * b); // output: 5 / 8
Console.WriteLine(a / b); // output: 10 / 4
}
}
암시적 변환을 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 |
다음과 같이 쌍으로 오버로드되어야 합니다: == 및 != , < 및 > , <= 및 >= . |
+= , -= , *= , /= , %= , &= , \|= , ^= <<= , >>= >>>= |
복합 할당 연산자는 C# 14 이상에서 오버로드할 수 있습니다. |
복합 할당 오버로드된 연산자는 다음 규칙을 따라야 합니다.
- 한정자를
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 이전에는 복합 연산자를 오버로드할 수 없습니다. 해당 이진 연산자를 오버로드하면 해당 복합 할당 연산자가 암시적으로 오버로드됩니다.
연산자 오버로드 해결
중요합니다
이 섹션은 C# 14 이상에 적용됩니다. C# 14 이전에는 사용자 정의 복합 할당 연산자와 인스턴스 증가 및 감소 연산자가 허용되지 않습니다.
와 같은 x
복합 할당 식에서 변수로 분류되는 경우 x «op»= y
인스턴스 연산자는 에 대한 «op»
정적 연산자보다 선호됩니다. 오버로드된 «op»=
연산자가 형식 x
에 대해 선언되지 않았거나 x
변수로 분류되지 않은 경우 정적 연산자가 사용됩니다.
후위 연산++
자에서 x
이 변수로 분류되지 않거나 식을 사용하는 경우에는 인스턴스x++
가 무시됩니다. 그렇지 않으면 인스턴스 operator ++
에 우선권이 부여됩니다. 예를 들면 다음과 같습니다.
x++; // Instance operator++ preferred.
y = x++; // instance operator++ isn't considered.
이 규칙의 이유는 증가하기 전의 y
값에 x
이 할당되어야 하기 때문입니다. 컴파일러는 참조 형식의 사용자 정의 구현에 대해 확인할 수 없습니다.
접두사 연산자 ++
의 경우, x
에서 ++x
가 변수로 분류되는 경우 인스턴스 연산자가 정적 단항 연산자보다 더 선호됩니다.
C# 언어 사양
자세한 내용은 C# 언어 사양의 다음 섹션을 참조하세요.
참고하십시오
.NET