在将可空的枚举内容与其底层主要内容进行转换时,会产生奇怪/不必要的编译器输出

时间:2016-06-02 05:47:29

标签: 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:

get_Foo():

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

set_Foo():

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

当我第一次看到这个时,对我来说似乎很直观。仅仅因为编译器将常规枚举视为其基础类型,并不自动意味着应该要求它们的可空表单。毕竟,Nullable<T>是它自己的结构。

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

get_Foo():

IL_0000: ldarg.0
IL_0001: ldfld System.Nullable`1[System.Int32] _foo
IL_0006: ret

set_Foo():

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld System.Nullable`1[System.Int32] _foo
IL_0007: ret

令人惊讶的是,该物业运作良好。我的问题是,为什么C#编译器会发出不必要的CIL?

1 个答案:

答案 0 :(得分:2)

您的更改会导致代码无法验证。如果您在其上运行peverify,您将获得以下内容:

  

[IL]:错误:[SO37583607.exe:SO37583607.TestClass :: get_Foo] [偏移量   0x00000007] [找到值'System.Nullable'1 [System.Int32]'] [预期   value'System.Nullable'1 [SO37583607.FooEnum]']意外的类型   叠加。

以下堆栈溢出答案试图解释可验证的代码:https://stackoverflow.com/a/4533532/284111

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