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

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

问题描述

我有一些用 [Conditional("XXX")] 标记的辅助方法.目的是在仅存在 XXX 条件编译符号时使方法有条件地编译.我们将其用于调试和跟踪功能,并且效果很好.

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.

在我研究条件编译如何工作的过程中,我发现有几个来源声明用 Conditional 属性标记的方法将放置在 IL 中,但不会执行对方法的调用.

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.

代码如何编译成 IL 但不执行?我如何验证行为是否确实如所描述的那样?我在 IL 方面做得不多,所以我在这方面的技能有点弱.

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.

推荐答案

这是由编译器控制的.所有带有 [Conditional] 的方法仍将包含在 MSIL 中,但将包含一个 .custom instance 行,详细说明 [Conditional].在方法调用者的编译时,编译器进行词法分析,然后进行语义分析和重载解析,并在您放置 [Conditional] 的方法中找到 .custom instance IL.因此它不会编译调用.

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 receiver and parameters of the call) is omitted.

如何验证?启动开发人员命令提示符,输入 ildasm 并打开相关的 dll/exe.检查调用者和被调用的 [Conditional] 方法.您将看到被调用的方法具有带有 .custom instance 的额外 IL,并且在您期望的地方省略了调用者行.使用以下代码在控制台应用程序上试用.

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.

为什么?在某些情况下,它使条件调用比使用 #if 更简单.请参阅 埃里克·利珀特: 条件编译和条件属性有什么区别?

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?");
    }
}

并且在相应的 MSIL 中,包含了 VerboseEmit,但不从 Main 调用:

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

奖励积分.查看控制台输出和 MSIL(相应地修改 Emit 方法):

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天全站免登陆