如何翻译"默认值(SOMETYPE)QUOT;从C#到CIL? [英] How to translate "default(SomeType)" from C# to CIL?
问题描述
我目前正在对涉及 System.Reflection.Emit
代码生成的问题。我试图找出CIL在地方发出,我会使用默认(SOMETYPE)
在C#。
我从Visual Studio 11 Beta版运行一些基本的实验。 JustDecompile 显示我默认值(布尔)
,默认值(字符串)
和默认(INT
:
.locals的init(
[0] BOOL V_0,
[1]串V_1,
[2]值类型[mscorlib程序]系统。 Nullable`1<&INT32 GT; V_2
)
//布尔b =默认值(布尔);
ldc.i4.0
stloc.0
//字符串s =默认值(字符串);
ldnull
stloc.1
// INT NI =默认值(INT);
ldloca.s V_2
initobj值类型[mscorlib程序] System.Nullable`1<&INT32 GT;
从这个情况来看,默认(T)
似乎得到由编译器到最合适的CIL对于给定类型的解决。
我去看看会发生什么更普遍的情况下,使用三种通用的方法:
T CreateStructDefault< T>()其中T:结构{返回默认值(T); } $ B $(B T)CreateClassDefault< T>()其中T:类{返回默认值(T); } $ B $(B T)CreateClassNull< T>()其中T:类{返回NULL; }
这三种方法产生同样的CIL方法体:
.locals的init(
[0] !!牛逼V_0,
[1]!牛逼V_1
)
IL_0000:NOP
IL_0001:ldloca.s V_1
IL_0003:initobj!牛逼
IL_0009:ldloc.1
IL_000a:stloc.0
IL_000b :br.s IL_000d
IL_000d:ldloc.0
IL_000e:RET
问:
我能从这一切的结论是C#的默认(SOMETYPE)
对应最密切CIL的…
-
initobj
对于非基本类型(除了字符串
?) -
ldc.iX.0
/ldnull
/等基本类型(加上字符串
)?
和为什么 CreateClassNull< T>
不仅仅是翻译成 ldnull
,但 initobj
呢?毕竟,在发出了字符串
(这也是引用类型) ldnull
。
我能从这一切的结论是C#的
默认(SOMETYPE)
最紧密对应CIL的initobj
对于非基本类型和ldc.i4.0
,ldnull
等基本类型?
块引用>
这是一个合理的总结,但更好的方式来想想是:如果C#编译器会进行分类
默认(T)
为编译时间常数的那么常量的值被发射。这是数字类型,假的布尔和null任何引用类型为零。如果它不会被归类为一个常数那么我们必须(1)发出一个临时变量,(2)获得临时的地址,(3)initobj通过其地址临时变量和(4)确保临时的值是。关于在需要时堆栈
为什么
CreateClassNull< T>
不只是翻译到ldnull,而是要initobj?
块引用>
好吧,让我们做你的方式,看看会发生什么:
...等
的.class民营汽车ANSI beforefieldinit P
扩展[mscorlib程序] System.Object的
{
。方法私人hidebysig静态! T!M<类T>()CIL管理
{
.maxstack 1
ldnull
沤
}
...等等
...
D:\> peverify foo.exe的
微软(R).NET框架PE验证。版本4.0.30319.17379
版权所有(c)Microsoft公司。版权所有。
[IL]:错误:
[D:\foo.exe:P :: M [T]]
[偏移00000001]
[发现Nullobjref NullReference']
[预期(装箱)'T']
型意外堆栈上。
1错误(S)验证D:\foo.exe
这很可能是为什么我们不这样做。
I'm currently working on a problem that involves
System.Reflection.Emit
code generation. I'm trying to figure out what CIL to emit in places where I would usedefault(SomeType)
in C#.I've run a few basic experiments from Visual Studio 11 Beta. JustDecompile shows me the following CIL output for
default(bool)
,default(string)
, anddefault(int?
:.locals init ( [0] bool V_0, [1] string V_1, [2] valuetype [mscorlib]System.Nullable`1<int32> V_2 ) // bool b = default(bool); ldc.i4.0 stloc.0 // string s = default(string); ldnull stloc.1 // int? ni = default(int?); ldloca.s V_2 initobj valuetype [mscorlib]System.Nullable`1<int32>
Judging from this,
default(T)
seems to get resolved by the compiler to the most appropriate CIL for the given types.
I went on to see what would happen in the more general case, using three generic methods:
T CreateStructDefault<T>() where T : struct { return default(T); } T CreateClassDefault<T>() where T : class { return default(T); } T CreateClassNull<T>() where T : class { return null; }
All three methods produce the same CIL method body:
.locals init ( [0] !!T V_0, [1] !!T V_1 ) IL_0000: nop IL_0001: ldloca.s V_1 IL_0003: initobj !!T IL_0009: ldloc.1 IL_000a: stloc.0 IL_000b: br.s IL_000d IL_000d: ldloc.0 IL_000e: ret
Question:
Can I conclude from all this that C#'s
default(SomeType)
corresponds most closely to CIL's…
initobj
for non-primitive types (exceptstring
?)ldc.iX.0
/ldnull
/ etc. for primitive types (plusstring
)?And why does
CreateClassNull<T>
not just translate toldnull
, but toinitobj
instead? After all,ldnull
was emitted forstring
(which is also a reference type).解决方案Can I conclude from all this that C#'s
default(SomeType)
corresponds most closely to CIL'sinitobj
for non-primitive types andldc.i4.0
,ldnull
, etc. for primitive types?That's a reasonable summary but a better way to think about it is: if the C# compiler would classify
default(T)
as a compile time constant then the value of the constant is emitted. That is zero for numeric types, false for bool, and null for any reference type. If it would not be classified as a constant then we must (1) emit a temporary variable, (2) obtain the address of the temporary, (3) initobj that temporary variable via its address and (4) ensure that the temporary's value is on the stack when it is needed.why does
CreateClassNull<T>
not just translate to ldnull, but to initobj instead?Well, let's do it your way and see what happens:
... etc .class private auto ansi beforefieldinit P extends [mscorlib]System.Object { .method private hidebysig static !!T M<class T>() cil managed { .maxstack 1 ldnull ret } ... etc
...
D:\>peverify foo.exe Microsoft (R) .NET Framework PE Verifier. Version 4.0.30319.17379 Copyright (c) Microsoft Corporation. All rights reserved. [IL]: Error: [d:\foo.exe : P::M[T]] [offset 0x00000001] [found Nullobjref 'NullReference'] [expected (unboxed) 'T'] Unexpected type on the stack. 1 Error(s) Verifying d:\foo.exe
That would probably be why we don't do that.
这篇关于如何翻译"默认值(SOMETYPE)QUOT;从C#到CIL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!