如何Conditional属性工作? [英] How does the Conditional attribute work?

查看:242
本文介绍了如何Conditional属性工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有标记一些辅助方法[条件(XXX)] 。的目的是使当只有XXX条件编译标志是本方法有条件地编译。我们使用这个用于调试和跟踪功能,它工作得很好。



在我的条件编译如何工作的研究,我发现了几个来源,说明方法标记有条件属性将被放置在IL而是调用将不被执行的方法。



如何代码获得编译成IL但不执行?我如何验证实际上是作为描述的行为?我没有做了很多与IL所以我的技能是在这方面有点弱。


解决方案

这是由编译器来控制。与所有的方法 [有条件] 仍然会包含在MSIL,但将包括 .custom实例详细介绍行在 [有条件] 。在编译时的方法调用者的编译器LEXES,然后执行语义分析和重载决议,并找到 .custom实例 IL在您放置方法 [有条件] 上。 。因此,它不编译调用



因此:编译器编译目标的方法,但无法编译任何呼叫以这种方法。注:该方法仍然存在,你仍然可以用反射调用它。请参见规范




拨打有条件的方法可能包括或省略取决于此符号是否是在调用点定义。如果该符号被定义,呼叫被包括在内;否则,省略了呼叫(包括调用的参数的评价)。




您如何验证呢?火起来的开发商命令提示符处,键入反汇编<&进入GT; 并打开相关的DLL / EXE文件。退房的主叫和被叫 [有条件] 方法。你会看到调用的方法有 .custom实例额外的IL,并且主叫方行省略,你期望的那样。尝试它与下面的代码的控制台应用程序。



为什么呢?这使得在某些情况下比使用#如果条件调用简单。请参见埃里克利珀:什么是条件编译和条件属性之间的区别?



<预类=郎-CS prettyprint-覆盖> 类节目
{
静态无效的主要(字串[] args)
{
AlwaysEmit();
DebugEmit();
VerboseEmit();
}

公共静态无效AlwaysEmit()
{
Console.WriteLine(传送我吧);
}

[条件(DEBUG)]
公共静态无效DebugEmit()
{
Console.WriteLine(柯克出);
}

[条件(冗长)]
公共静态无效VerboseEmit()
{
Console.WriteLine(再说一遍? );
}
}

和相应MSIL, VerboseEmit 被包括在内,而不是从名为:

 。方法私人hidebysig静态无效的主要(字串[] args)CIL管理
{
.entrypoint
//代码大小14(0xe)
.maxstack 8
IL_0000:NOP
IL_0001:调用无效RateScope.SdrApi.UploaderConsoleApp.Program :: AlwaysEmit()
IL_0006:NOP
IL_0007:拨打无效RateScope.SdrApi.UploaderConsoleApp.Program: :DebugEmit()
IL_000c:NOP
IL_000d:RET
} //方法程序结束::主要



。方法公开hidebysig静态无效VerboseEmit()CIL管理
{
.custom实例无效[mscorlib程序] System.Diagnostics.ConditionalAttribute ::。ctor的(字符串)
=(01 00 07 56 45 52 42 53 4F 45 00 00)// ... .. VERBOSE
//代码大小13(0xd中)
.maxstack 8
IL_0000:NOP
IL_0001:ldstr 再说一次\?
IL_0006:呼叫无效[mscorlib程序] System.Console:的WriteLine(字符串)
IL_000b:NOP
IL_000c:RET
} //方法程序结束:: VerboseEmit

奖励积分。查看控制台输出和MSIL这个(修改相应的的Emit方法):

 静态无效的主要(字串[] args )
{
INT callCount = 0;
AlwaysEmit(++ callCount);
VerboseEmit(++ callCount);
DebugEmit(++ callCount);
Console.WriteLine(呼叫数=+ callCount);
到Console.ReadLine();
}


I have some helper methods marked with [Conditional("XXX")]. The intent is to make the methods conditionally compile when only the XXX conditional compilation symbol is present. We're using this for debugging and tracing functionality and it works quite well.

During my research on how the conditional compilation works, I found several sources stating methods tagged with the Conditional attribute will be placed in the IL but calls to the methods will not be executed.

How does code get compiled into IL but not executed? How can I verify the behavior is actually as described? I haven't done much with IL so my skills are little weak in this area.

解决方案

This is controlled by the compiler. All methods with [Conditional] will still be included in the MSIL, but will include a .custom instance line that details the [Conditional]. At compile time for a method caller the compiler lexes, then does semantic analysis and overload resolution, and finds the .custom instance IL in the method you placed [Conditional] on. It therefore doesn't compile the call.

So: the compiler compiles the target method, but does not compile any call to that method. Note: the method is still there and you could still call it with reflection. See the spec

Calls to a conditional method are either included or omitted depending on whether this symbol is defined at the point of the call. If the symbol is defined, the call is included; otherwise, the call (including evaluation of the parameters of the call) is omitted.

How can you verify it? Fire up the developer command prompt, type ildasm <enter> and open the relevant dlls/exes. Check out the caller and the called [Conditional] methods. You'll see the called methods have the extra IL with .custom instance, and the caller lines are omitted where you would expect. Try it on a console application with the code below.

Why? It makes conditional calls simpler in some cases than using #if. See Eric Lippert: What's the difference between conditional compilation and the conditional attribute?

class Program
{
    static void Main(string[] args)
    {
        AlwaysEmit();
        DebugEmit();
        VerboseEmit();
    }

    public static void AlwaysEmit()
    {
        Console.WriteLine("Beam me up");
    }

    [Conditional("DEBUG")]
    public static void DebugEmit()
    {
        Console.WriteLine("Kirk out");
    }

    [Conditional("VERBOSE")]
    public static void VerboseEmit()
    {
        Console.WriteLine("Say that again?");
    }
}

And in the corresponding MSIL, VerboseEmit is included, but not called from Main:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       14 (0xe)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  call       void RateScope.SdrApi.UploaderConsoleApp.Program::AlwaysEmit()
  IL_0006:  nop
  IL_0007:  call       void RateScope.SdrApi.UploaderConsoleApp.Program::DebugEmit()
  IL_000c:  nop
  IL_000d:  ret
} // end of method Program::Main

...

.method public hidebysig static void  VerboseEmit() cil managed
{
  .custom instance void [mscorlib]System.Diagnostics.ConditionalAttribute::.ctor(string)
     = ( 01 00 07 56 45 52 42 4F 53 45 00 00 ) // ...VERBOSE..
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Say that again\?"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::VerboseEmit

Bonus points. Look at the console output and the MSIL for this (modify the Emit methods accordingly):

static void Main(string[] args)
{
    int callCount = 0;
    AlwaysEmit(++callCount);
    VerboseEmit(++callCount);
    DebugEmit(++callCount);
    Console.WriteLine("Call count = " + callCount);
    Console.ReadLine();
}

这篇关于如何Conditional属性工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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