C#9.0의 범위 모드의 switch가 비교적 똑똑하게 컴파일되었다

18149 단어 .NETC#tech

범위 모드의 switch식 사용하기


C#9.0에서는 switch에서 비교 연산을 지정할 수 있습니다.
원시 코드
public class C
{
    public int Expr(int num) => num switch
    {
            <=0 => -1,
            < 10 => 0,
            < 20 => 1,
            < 30 => 2,
            < 40 => 3,
            < 50 => 4,
            < 60 => 5,
            _ => -1,
    };
}
위 코드의 컴파일 결과(IL을 C#로 컴파일)는 다음과 같습니다.
컴파일 결과
public class C
{
    public int Expr(int num)
    {
        if (num < 30)
        {
            if (num < 10)
            {
                if (num <= 0)
                {
                    return -1;
                }
                return 0;
            }
            if (num < 20)
            {
                return 1;
            }
            return 2;
        }
        if (num < 50)
        {
            if (num < 40)
            {
                return 3;
            }
            return 4;
        }
        if (num < 60)
        {
            return 5;
        }
        return -1;
    }
}
2분이나 검색했어.
만약 이렇다면if문을 열거해도 큰 차이가 없지만 2분 동안 검색하면if문이 실행되는 횟수는log입니다2회 정도.단점 없는 고속화를 기대할 수 있기 때문에 범위를 열거한 부분에 적극적으로 switch식으로 쓰는 것이 좋다.
그나저나 switch 문장에서도 점프표를 만들 수 없는 상황에서 2점 검색으로 전환할 수 있을 것 같다.
http://engineering.grani.jp/entry/2017/02/20/175816

추기


'나쁜 점은 없다'고 썼지만'대부분의 경우0 <= num && num < 10'는 일치하는 빈도가 매우 높으면 일치하는 빈도가 높은 순서에 따라 나열if문이 2분 탐색보다 빠른 것 같다.

or 사용 시

or도 사용해 보았어요.
원시 코드
public class C
{
    public int Expr(int num) => num switch
    {
            <=0 => -1,
            < 10 or > 600 => 0,
            < 20 or > 500 => 1,
            < 30 or > 400 => 2,
            < 40 or > 300 => 3,
            < 50 or > 200 => 4,
            < 60 or > 100 => 5,
            _ => -1,
    };
}
컴파일 결과는 다음과 같다.
컴파일 결과
public class C
{
    public int Expr(int num)
    {
        if (num > 100)
        {
            if (num > 300)
            {
                if (num > 500)
                {
                    if (num > 600)
                    {
                        goto IL_0061;
                    }
                    goto IL_0065;
                }
                if (num > 400)
                {
                    goto IL_0069;
                }
                goto IL_006d;
            }
            if (num > 200)
            {
                goto IL_0071;
            }
        }
        else
        {
            if (num < 30)
            {
                if (num < 10)
                {
                    if (num > 0)
                    {
                        goto IL_0061;
                    }
                    return -1;
                }
                if (num < 20)
                {
                    goto IL_0065;
                }
                goto IL_0069;
            }
            if (num < 50)
            {
                if (num < 40)
                {
                    goto IL_006d;
                }
                goto IL_0071;
            }
            if (num >= 60)
            {
                return -1;
            }
        }
        return 5;
        IL_0065:
        return 1;
        IL_0061:
        return 0;
        IL_0071:
        return 4;
        IL_0069:
        return 2;
        IL_006d:
        return 3;
    }
}
goto 약간 스파게티 같은데, 이것도 2점 탐색이다.

결론


열거 범위 검사 시 switch식이 더욱 효율적입니다!

좋은 웹페이지 즐겨찾기