C# 在将可为空的枚举强制转换到它们的基础枚举时,会出现奇怪/不必要的编译器输出

C# 在将可为空的枚举强制转换到它们的基础枚举时,会出现奇怪/不必要的编译器输出,c#,.net,compilation,C#,.net,Compilation,考虑以下代码: public enum FooEnum : int { Foo = 0, Bar = 1, Qux = 2 } public class TestClass { private int? _foo; public FooEnum? Foo { get { return (FooEnum?)_foo; } set { _foo = (int?)value; } } } 查看生成的CIL:

考虑以下代码:

public enum FooEnum : int
{
    Foo = 0,
    Bar = 1,
    Qux = 2
}

public class TestClass
{
    private int? _foo;

    public FooEnum? Foo
    {
        get { return (FooEnum?)_foo; }
        set { _foo = (int?)value; }
    }
}
查看生成的CIL:

get_Foo():

set_Foo():

当我第一次看到这一点时,我似乎很直觉。仅仅因为编译器将常规枚举视为它们的底层类型,并不自动意味着应该要求它们的可空形式。毕竟,
Nullable
是它自己的结构

然而,这就是它变得奇怪的地方。我使用Mono.Cecil重新编写get和set方法,使用的指令将被视为不可为null:

get_Foo():

set_Foo():


令人惊讶的是,这家酒店运转良好。我的问题是,为什么C编译器会发出不必要的CIL?

您的更改会导致代码无法验证。如果你在上面运行,你会得到如下结果:

[IL]:错误:[SO37583607.exe:SO37583607.TestClass::get_Foo][offset 0x00000007][found value'System.Nullable'1[System.Int32]][expected 值“System.Nullable”1[SO37583607.FooEnum]]在 堆叠

以下堆栈溢出回答试图解释什么是可验证代码:

为了回答您的问题,编译器会发出此代码,以确保其可验证。

您是否尝试在代码上运行?
IL_0000: ldarg.0
IL_0001: ldfld System.Nullable`1[System.Int32] _foo
IL_0006: stloc.0
IL_0007: ldloca.s System.Nullable`1[System.Int32] (0)
IL_0009: call Boolean get_HasValue()
IL_000e: brtrue.s IL_001a
IL_0010: ldloca.s System.Nullable`1[MyAssembly.FooEnum] (1)
IL_0012: initobj System.Nullable`1[MyAssembly.FooEnum]
IL_0018: ldloc.1
IL_0019: ret
IL_001a: ldloca.s System.Nullable`1[System.Int32] (0)
IL_001c: call Int32 GetValueOrDefault()
IL_0021: newobj Void .ctor(MyAssembly.FooEnum)
IL_0026: ret
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stloc.0
IL_0003: ldloca.s System.Nullable`1[MyAssembly.FooEnum] (0)
IL_0005: call Boolean get_HasValue()
IL_000a: brtrue.s IL_0017
IL_000c: ldloca.s System.Nullable`1[System.Int32] (1)
IL_000e: initobj System.Nullable`1[System.Int32]
IL_0014: ldloc.1
IL_0015: br.s IL_0023
IL_0017: ldloca.s System.Nullable`1[MyAssembly.FooEnum] (0)
IL_0019: call MyAssembly.FooEnum GetValueOrDefault()
IL_001e: newobj Void .ctor(Int32)
IL_0023: stfld System.Nullable`1[System.Int32] _foo
IL_0028: ret
IL_0000: ldarg.0
IL_0001: ldfld System.Nullable`1[System.Int32] _foo
IL_0006: ret
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld System.Nullable`1[System.Int32] _foo
IL_0007: ret