Open7

Enumの構文解析に特別扱いがあるっぽい話

ピン留めされたアイテム
KeiKei

当初はnullableなenumのcaseラベルでコンパイルエラー起こしたとこから

絶対他に誰か踏んでそうに思うのだが、探し方が悪いのか全然情報が見つからない
試したキーワード C# nullable enum case issue 辺り
環境はNet Core3.1 C#8
.NET5 C#9 でも同様だった

KeiKei

これはOK

class TestClass
{
    public TestEnum TestEnum { get; set; }

    public void Hoge()
    {
        switch (TestEnum)
        {
            case TestEnum.Item1:
            case TestEnum.Item2:
            case TestEnum.Item3:
            case TestEnum.Item4:
            default:
                break;
        }
    }

    public void Fuga()
    {
        var n = TestEnum switch
        {
            TestEnum.Item1 => "1",
            TestEnum.Item2 => "2",
            TestEnum.Item3 => "3",
            TestEnum.Item4 => "4",
            _ => ""
        };
    }
}

public enum TestEnum
{
    Item1, Item2, Item3, Item4
}
KeiKei

これはNG

class TestClass
{
    public TestEnum? TestEnum { get; set; }

    public void Hoge()
    {
        switch (TestEnum)
        {
            case TestEnum.Item1: // エラー (TestEnumがプロパティを参照する)
            case TestEnum.Item2: // 同上
            case TestEnum.Item3: // 同上
            case TestEnum.Item4: // 同上
            default:
                break;
        }
    }

    public void Fuga()
    {
        var n = TestEnum switch
        {
            TestEnum.Item1 => "1", // エラー (TestEnumがプロパティを参照する)
            TestEnum.Item2 => "2", // 同上
            TestEnum.Item3 => "3", // 同上
            TestEnum.Item4 => "4", // 同上
            _ => ""
        };
    }
}
KeiKei

これはOK (=nullableなenumがラベルに使えないというわけではない)

class TestClass
{
    public TestEnum? TestEnumProp { get; set; }

    public void Hoge()
    {
        switch (TestEnumProp)
        {
            case TestEnum.Item1:
            case TestEnum.Item2:
            case TestEnum.Item3:
            case TestEnum.Item4:
            default:
                break;
        }
    }

    public void Fuga()
    {
        var n = TestEnumProp switch
        {
            TestEnum.Item1 => "1",
            TestEnum.Item2 => "2",
            TestEnum.Item3 => "3",
            TestEnum.Item4 => "4",
            _ => ""
        };
    }
}
KeiKei

一番影響が少なそうな回避策

using ETestEnum = ...TestEnum;

……

class TestClass
{
    public ETestEnum? TestEnum { get; set; }

    public void Hoge()
    {
        switch (TestEnum)
        {
            case ETestEnum.Item1:
            case ETestEnum.Item2:
            case ETestEnum.Item3:
            case ETestEnum.Item4:
            default:
                break;
        }
    }

    public void Fuga()
    {
        var n = TestEnum switch
        {
            ETestEnum.Item1 => "1",
            ETestEnum.Item2 => "2",
            ETestEnum.Item3 => "3",
            ETestEnum.Item4 => "4",
            _ => ""
        };
    }
}


public enum TestEnum
{
    Item1, Item2, Item3, Item4
}
KeiKei

・enum以外で似たようなことやろうとすると全部死ぬ (例:intでプロパティ作って同名クラスのconst参照)
・anotationでクラス参照しようとした場合も同名プロパティがあればそちらが優先される
上から考えるとswitchの構文解析の際に条件がenumの場合だけ特殊な処理が入っていると考えるのが妥当?

KeiKei

switchに限らずenumの構文解析に特別扱いがあるのでは?

TestEnum TestEnum = TestEnum.Item1; // OK
TestEnum? TestEnum = TestEnum.Item1; // NG
int TestEnum = TestEnum.Item1 // NG
var TestEnum = TestEnum.Item1 // NG