简体   繁体   English

如何将“default(SomeType)”从C#翻译成CIL?

[英]How to translate “default(SomeType)” from C# to CIL?

I'm currently working on a problem that involves System.Reflection.Emit code generation. 我目前正在处理涉及System.Reflection.Emit代码生成的问题。 I'm trying to figure out what CIL to emit in places where I would use default(SomeType) in C#. 我试图弄清楚在C#中我将使用default(SomeType)地方发出什么CIL。

I've run a few basic experiments from Visual Studio 11 Beta. 我从Visual Studio 11 Beta运行了一些基本实验。 JustDecompile shows me the following CIL output for default(bool) , default(string) , and default(int? : JustDecompile向我显示以下CIL输出的default(bool)default(string)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. 从这一点来看, default(T)似乎被编译器解析为给定类型的最合适的CIL。


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: 这三种方法都生成相同的CIL方法体:

.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… 我能否从这一切中得出结论:C#的default(SomeType)最接近CIL ...

  • initobj for non-primitive types (except string ?) 用于非基本类型的initobjstring除外?)
  • ldc.iX.0 / ldnull / etc. for primitive types (plus string )? ldc.iX.0 / ldnull / etc.原始类型(加上string )?

And why does CreateClassNull<T> not just translate to ldnull , but to initobj instead? 又为何CreateClassNull<T>不只是翻译为ldnull ,但initobj呢? After all, ldnull was emitted for string (which is also a reference type). 毕竟, ldnull是为string发出的(它也是一个引用类型)。

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? 我可以从这一切得出结论,C#的default(SomeType)最接近CIL的非基本类型的initobj和原始类型的ldc.i4.0ldnull等吗?

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. 这是一个合理的总结,但更好的思考方式是:如果C#编译器将default(T)分类为编译时常量,则会发出常量的值。 That is zero for numeric types, false for bool, and null for any reference type. 数字类型为零,bool为false,任何引用类型为null。 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. 如果它不被归类为常数,那么我们必须(1)发出一个临时变量,(2)通过其地址获取临时变量的地址,(3)initobj该临时变量和(4)确保临时变量的值是在需要时在堆栈上。

why does CreateClassNull<T> not just translate to ldnull, but to initobj instead? 为什么CreateClassNull<T>不只是转换为ldnull,而是转换为initobj?

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. 这可能就是我们不这样做的原因。

Yes, that's what default does. 是的,那是default You are correct in deducing it's just syntactic sugar for basically 0 (or equivalents). 你推断它只是语法糖基本为0 (或等价物)是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM