true 연산자와 false 연산자 — 객체를 Boolean 값처럼 다루기

true 연산자와 false 연산자 — 객체를 Boolean 값처럼 다루기

C#에는 객체가 '참(true)' 인지 '거짓(false)' 인지를 물어볼 때 쓰는 true 연산자와 false 연산자가 있어요. 이 두 연산자를 오버로드하면 여러분이 만든 타입을 Boolean 값처럼 다룰 수 있는데요, 오늘은 이 연산자가 어떤 의미를 갖고 어떻게 활용되는지를 차근차근 살펴볼게요.

출처: Microsoft Learn

본문

true 연산자는 피연산자가 확실히 참(true) 임을 나타낼 때 booltrue를 돌려줍니다. 반대로 false 연산자는 피연산자가 확실히 거짓(false) 임을 나타낼 때 booltrue를 돌려줘요. 여기서 조금 헷갈릴 수 있는데요, false 연산자가 "거짓이다"라고 답할 때 false가 아니라 true를 반환한다는 점을 기억해 두세요. 즉 두 연산자 모두 "예, 맞습니다"라고 대답하는 상황이면 true를 반환하는 방식이에요.

[!INCLUDEcsharp-version-note]

true 연산자와 false 연산자를 둘 다 구현하는 타입은 다음 의미를 따라야 합니다.

  • "이 객체는 참인가?"라는 질문은 true 연산자로 해결됩니다. 객체가 참이라면 true 연산자가 true를 반환해서, "네, 이 객체는 참입니다"라고 대답하는 거죠.
  • "이 객체는 거짓인가?"라는 질문은 false 연산자로 해결됩니다. 객체가 거짓이라면 false 연산자가 true를 반환해서, "네, 이 객체는 거짓입니다"라고 대답합니다.

여기서 꼭 알아두셔야 할 점이 있어요. true 연산자와 false 연산자는 서로 보완 관계가 보장되지 않습니다. 즉 같은 피연산자에 대해 true 연산자와 false 연산자가 둘 다 boolfalse를 반환할 수도 있어요. 그리고 이 두 연산자 중 하나만 정의할 수는 없고, 하나를 정의하면 반드시 다른 하나도 함께 정의해야 합니다.

[!TIP] 3값 논리(three-valued logic)를 지원해야 한다면 — 예를 들어 3값 Boolean 타입을 지원하는 데이터베이스를 다룰 때처럼요 — bool? 타입을 사용하는 게 좋습니다. C#은 bool? 피연산자에 대해 3값 논리를 지원하는 & 연산자와 | 연산자를 제공해요. 자세한 내용은 Boolean 논리 연산자 문서의 Nullable Boolean 논리 연산자 섹션을 참고하세요.

Boolean 식

true 연산자가 정의된 타입은 제어 흐름을 결정하는 조건식의 결과 타입이 될 수 있어요. 구체적으로는 if 문, do 문, while 문, for 문에서, 그리고 조건 연산자 ?:에서 그 타입을 조건식으로 쓸 수 있어요. 자세한 내용은 C# 언어 사양Boolean 식 섹션을 참고하세요.

사용자 정의 조건부 논리 연산자

true 연산자와 false 연산자가 모두 정의된 타입이 논리 OR 연산자 | 또는 논리 AND 연산자 &오버로드하면, 그 타입의 피연산자에 대해 각각 조건부 논리 OR 연산자 || 또는 조건부 논리 AND 연산자 &&를 평가할 수 있게 됩니다. 자세한 내용은 C# 언어 사양사용자 정의 조건부 논리 연산자 섹션을 참고하세요.

예제

다음 예제는 true 연산자와 false 연산자를 모두 정의한 타입을 보여줍니다. 이 타입은 논리 AND 연산자 &도 오버로드하는데, 그 덕분에 이 타입의 피연산자에 대해 && 연산자도 평가할 수 있어요.

public struct LaunchStatus
{
    public static readonly LaunchStatus Green = new LaunchStatus(0);
    public static readonly LaunchStatus Yellow = new LaunchStatus(1);
    public static readonly LaunchStatus Red = new LaunchStatus(2);

    private int status;

    private LaunchStatus(int status)
    {
        this.status = status;
    }

    public static bool operator true(LaunchStatus x) => x == Green || x == Yellow;
    public static bool operator false(LaunchStatus x) => x == Red;

    public static LaunchStatus operator &(LaunchStatus x, LaunchStatus y)
    {
        if (x == Red || y == Red || (x == Yellow && y == Yellow))
        {
            return Red;
        }

        if (x == Yellow || y == Yellow)
        {
            return Yellow;
        }

        return Green;
    }

    public static bool operator ==(LaunchStatus x, LaunchStatus y) => x.status == y.status;
    public static bool operator !=(LaunchStatus x, LaunchStatus y) => !(x == y);

    public override bool Equals(object obj) => obj is LaunchStatus other && this == other;
    public override int GetHashCode() => status;
}

public class LaunchStatusTest
{
    public static void Main()
    {
        LaunchStatus okToLaunch = GetFuelLaunchStatus() && GetNavigationLaunchStatus();
        Console.WriteLine(okToLaunch ? "Ready to go!" : "Wait!");
    }

    static LaunchStatus GetFuelLaunchStatus()
    {
        Console.WriteLine("Getting fuel launch status...");
        return LaunchStatus.Red;
    }

    static LaunchStatus GetNavigationLaunchStatus()
    {
        Console.WriteLine("Getting navigation launch status...");
        return LaunchStatus.Yellow;
    }
}

이 예제에서 && 연산자의 단락(short-circuit) 동작을 눈여겨보세요. GetFuelLaunchStatus 메서드가 LaunchStatus.Red를 반환하면 && 연산자의 오른쪽 피연산자는 평가되지 않습니다. 그 조건은 확실히 거짓이고, 논리 AND의 결과는 오른쪽 피연산자의 값에 의존하지 않기 때문이에요. 위 예제의 출력 결과는 다음과 같습니다.

Getting fuel launch status...
Wait!

더 알아보기