请考虑以下代码:
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?
答案 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
因此,为了回答您的问题,编译器会发出此代码,以确保它是可验证的。