加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

从Trace和Debug来看条件编译(Conditional Compilation)

发布时间:2020-12-16 09:05:54 所属栏目:asp.Net 来源:网络整理
导读:条件编译,顾名思义,就是根据在编译时指定的条件决定最后需要编译的代码。条件编译是我们可以针对某些特性的环境编写相应的代码,比如有写的代码只需要在Debug模式下才需要执行,有些代码仅仅是为了在SIT或者UAT环境下有效地进行Troubleshooting,而在Produ

条件编译,顾名思义,就是根据在编译时指定的条件决定最后需要编译的代码。条件编译是我们可以针对某些特性的环境编写相应的代码,比如有写的代码只需要在Debug模式下才需要执行,有些代码仅仅是为了在SIT或者UAT环境下有效地进行Troubleshooting,而在Production环境下则不应该执行。通过条件编译机制,我们可以针对某中特定的“条件编译符(Conditional Compilation Symbol)”编写相应的代码。在进行最终编译的时候,通过指定的条件编译符,编译器判断这些特殊的代码是否应该被编译。

目录:
一、Trace.WriteLine() V.S. Debug.WriteLine()
二、一个重要的特性ConditionalAttribute
三、一个条件编译的例子
四、看看编译后的代码
五、ConditionalAttribute与#if/#endif

一、Trace.WriteLine() V.S. Debug.WriteLine()

为了让大家对条件编译有一个相对直观的认识,我们举一个大家很熟悉的例子。我们都知道,在Trace和Debug是定义在System.Diagnostics命名空间下两个重要的用于应用程序“诊断”的类,我们可以通过它们的静态方法Write或者WriteLine方法写入一些追踪和调试消息。如果你对Trace和Debug具有一定的了解,你应该知道定义在它们之中的Write或者WriteLine方法具有相同的实现,最终都是将消息传递给配置的TraceListener,并被写入相应的目标存储中

为了演示Trace和Debug消息写入机制,我写了一个非常简单的程序。首先我通过继承TraceListener,写了一个自定义的TraceListener:ConsoleTraceListener。ConsoleTraceListener实现了抽象方法Write和WriteLine,直接将消息通过控制台打印出来。这个ConsoleTraceListener定义如下:

   1: public class ConsoleTraceListener : TraceListener
   3:     override void Write(string message)
   5:         Console.Write(message);
   7:? 
   9:     {
  11:     }
    
   2: <configuration>
   7:       </   9:     10: >

最后我们编写如下的代码,分别调用Debug和Trace的WriteLine方法写入一段指定的消息:

3: Trace.WriteLine("This is message written by invoking Trace.WriteLine method.");
   5: }

我们指定的消息将会通过ConsoleTraceListener直接写入到控制台上:

2: This is message written by invoking Debug.WriteLine method.

二、一个重要的特性ConditionalAttribute

从上面的例子,我们基本上可以看出定义在Trace和Debug中的WriteLine方法在实现上并没有什么不同之处,最终的诊断消息的写入操作都是通过配置好的TraceListener列表来完成的。如果你通过Reflector来看看WriteLine方法在两者中的实现,你更会发现方法的实现逻辑是一样的

//...
   5:        6:     {
   8:     }
  10:? 
  12: {
  15:       16:     {
  18:     }
   1: [Conditional("PRODUCTION")]
   3: {
   5:     {
   7:     }
   3:     var identity            = new GenericIdentity("Foo");
   5:     Thread.CurrentPrincipal = principal;
   7:     Console.WriteLine("Continue...");
   1: Unhandled Exception: System.Security.SecurityException: Access denied!
   3: CompilationProgram.cs:line 28
   5: ditionalCompilationProgram.cs:line 19

四、看看编译后的代码

我们之前已经说了,条件编译就是在编译的时候将指定的条件编译符动态去过滤不需要参与编译的源代码。对于调用了ConditionalAttribute特性的方法,只有里面的参数和指定的条件编译符一致,相应的代码才会参与编译。以上面的代码为例,在我们没有指定PRODUCTION条件编译符的情况下,编译出来包含在程序集中的代码等同于下面:

7: }

五、ConditionalAttribute与#if/#endif

我个人推荐尽量将条件编译的代码封装到一个方法中,并在上面应用ConditionalAttribute特性。如果不能,才使用#if/#endif这样的条件编译指令。如果我们采用内联的方式来实现基于上面的授权检验,我们可以直接使用#if/#endif块来封装授权逻辑。相应的代码如下: