如何翻译"默认值(SOMETYPE)QUOT;从C#到CIL? [英] How to translate "default(SomeType)" from C# to CIL?

查看:191
本文介绍了如何翻译"默认值(SOMETYPE)QUOT;从C#到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 use default(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), and default(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 (except string?)
  • ldc.iX.0 / ldnull / etc. for primitive types (plus string)?

And why does CreateClassNull<T> not just translate to ldnull, but to initobj instead? After all, ldnull was emitted for string (which is also a reference type).

解决方案

Can I conclude from all this that C#'s default(SomeType) corresponds most closely to CIL's initobj for non-primitive types and ldc.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.

这篇关于如何翻译&QUOT;默认值(SOMETYPE)QUOT;从C#到CIL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆