找回密码
 立即注册
首页 业界区 业界 [你必须知道的.NET]第三十五回,判断dll是debug还是rele ...

[你必须知道的.NET]第三十五回,判断dll是debug还是release,这是个问题

唐嘉懿 2025-5-29 19:56:02
anytao.net | 《你必须知道的.NET》网站 | Anytao技术博客 
发布日期:2009.12.29 作者:Anytao
© 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处。

问题的提出 

晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码方式来判断一个dll或者exe为debug build还是release build?由于没有太多的讨论,所以我只好自己找点儿办法,试图解决这个问题,为夜生活带点刺激。于是,便有了本文的探索和分析。
当然,为了充分的调动起大家的主意,省去不必要的google操作,我觉得有必要对Debug和Release两种模式的异同进行一点提纲挈领式的分析,从而为接下来的解决方案打好基础。
Debug & Release

我们应用Visual Studio对代码文件进行F5操作(Build)时,实际是发生了一系列语法检查、词法检查和编译过程,通常情况下我们有两种Build模式,这就是常说的Debug Build和Release Build。望文知意,Debug Build模式通常应用于开发时,便于调试反馈;而Release Build则应用于部署时,这是因为Release模式下,编译器做了很多的优化操作(代码冗余、循环优化等),省去了对调试信息的记录。因此,两种Build模式是各不相同的,我们对其二者进行一点总结如下:

  • Debug用于开发时,Release用于部署时。
  • Debug模式下,将产生pdb文件,用于保存状态信息和调试信息;Release模式下,不产生调试信息,也没有pdb文件。
  • Debug模式下,System.Diagnostics.Debug.Write(或WriteLine)可以向跟踪窗口(Output)输出跟踪信息;而Release模式下,System.Diagnostics.Debug.WriteLine将被忽略。不过,可以考虑System.Diagnostics.Trace.Write,其人缘较好,对Debug和Release左右通吃,都可输出调试信息。
  • Debug模式下,#define DEBUG将作为默认预定义常量,参与编译过程;而在Release模式下,该预编译将被省略。例如如果执行:
  1. #if DEBUG
  2.     Console.WriteLine("Hi");
  3. #endif
复制代码
在Debug模式下,Console.WriteLine(“Hi”)将参与编译,而Release模式下,会忽略该语句的执行。不过,如果你手动添加
  1. #define DEBUG
复制代码
在两种模式下,都会执行Console.WriteLine(“Hi”)的编译。究其原因,是Visual Studio在默认情况下预定义了#define DEBUG,我们可以通过开关来设置:
1.png

关于预编译指令可详查《你必须知道的.NET》的相关章节。
解决方案

既然对Debug Build和Release Build有个基本的了解,那么也由此可以推断我们解决开篇问题的依据。在.NET中以DebuggableAttribute来控制CLR如何处理模块代码规则,而属性IsJITTrackingEnabled属性来标识运行库在代码生成过程中是否跟踪调试信息的标识,如果IsJITTrackingEnabled为true,表示运行库跟踪调试信息,可推断为Debug Build模式;如果IsJITTrackingEnabled为false,表示运行库没有跟踪调试信息,可推为Release Build模式。所以,解决的方案,最终着眼于对IsJITTrackingEnabled信息的获取上,可想而知,最简单的办法莫过于神兵利器——反射。
那么,我们开始吧。
构建

首先我们创建一个AnyContext来承载通用的上下文服务,在这里主要包含的就是:
  1. /// <summary>
  2. /// A common context
  3. /// </summary>
  4. /// <remarks>
  5. /// Anytao, http://www.anytao.com
  6. /// </remarks>
  7. public class AnyContext : IAnyObject
  8. {
  9.     public static DebugMode GetDebugMode(string assemblyName)
  10.     {     
  11.     }
  12. }
  13. 其中,DebugMode是一个简单的枚举:
复制代码
  1. /// <summary>
  2. /// Debug mode type
  3. /// </summary>
  4. /// <remarks>
  5. /// Anytao, http://www.anytao.com
  6. /// </remarks>
  7. public enum DebugMode
  8. {
  9.     Debug,
  10.     Release
  11. }
复制代码
可向而知,我们需要实现一个根据Assembly信息获取DebuggrableAttribute的Helper类,既然是Helper类我们希望能够兼顾各种情况,因此通过泛型方法是做好的选择,具体实现如下:
  1. /// <summary>
  2. /// Common helper
  3. /// </summary>
  4. /// <remarks>
  5. /// Anytao, http://www.anytao.com
  6. /// </remarks>
  7. public static class Utils
  8. {
  9.     /// <summary>
  10.     /// Get GetCustomAttribute
  11.     /// </summary>
  12.     /// <typeparam name="T">CustomAttribute Type</typeparam>
  13.     /// <param name="provider"></param>
  14.     /// <returns></returns>
  15.     public static T GetCustomAttribute<T>(this ICustomAttributeProvider provider)
  16.         where T : Attribute
  17.     {
  18.         var attributes = provider.GetCustomAttributes(typeof(T), false);
  19.         return attributes.Length > 0 ? attributes[0] as T : default(T);
  20.     }
  21. }
复制代码
此处的GetCustomAttribute被实现为扩展方法,那么任何实现了ICustomAttributeProvider接口的类型,都可以通过其获取CustomAttribute了,例如:Type、Assembly、Module、MethodInfo,都可以实现对GetCustomAttribute的调用。
接下来,GetDebugMode的逻辑就变得很简单,我们传入assembly路径即可获取DebuggrableAttribute,并由此推导IsJITTrackingEnabled的情况:
  1. public static DebugMode GetDebugMode(string assemblyName)
  2. {
  3.     if (string.IsNullOrEmpty(assemblyName))
  4.     {
  5.         throw new ArgumentNullException("assemblyName");
  6.     }
  7.     DebugMode ret = DebugMode.Debug;
  8.     try
  9.     {
  10.         // Get assebly by name
  11.         Assembly ass = Assembly.LoadFile(assemblyName);
  12.         // Get DebuggableAttribute info
  13.         DebuggableAttribute att = ass.GetCustomAttribute<DebuggableAttribute>();
  14.         ret = att.IsJITTrackingEnabled ? DebugMode.Debug : DebugMode.Release;
  15.     }
  16.     catch (Exception)
  17.     {
  18.         throw;
  19.     }
  20.     return ret;
  21. }
  22. 好了,这就是一个简单的判断逻辑,在AnyContext中包含了很多诸如此类的上下文定义,而GetDebugMode提供了本文开头的解决方案。
复制代码
测试


  • 新建两个project,并分别以Debug模式和Release模式编译,生成对应的exe(或dll):

    • debugass.exe
    • releaseass.exe

  • 新建TestProject,并对GetDebugMode进行测试如下:
  1. [TestClass]
  2. public class AnyContextTest
  3. {
  4.     [TestMethod]
  5.     public void TestIsDebugOrRelease()
  6.     {
  7.         // Arrange
  8.         string ass1 = @"D:\debugass.exe";
  9.         string ass2 = @"D:\releaseass.exe";
  10.         // Act
  11.         string mode1 = AnyContext.GetDebugMode(ass1).ToString();
  12.         string mode2 = AnyContext.GetDebugMode(ass2).ToString();
  13.         // Asset
  14.         Assert.AreEqual(mode1, "Debug");
  15.         Assert.AreEqual(mode2, "Release");
  16.     }
  17. }
复制代码
一切OK,你不妨试试。
 
注:本测试在.NET 2.0及其以上版本测试通过,如您有更多精力,可对其以下版本进行分析。
 
参考文献:

  • ms-help://MS.MSDNQTR.v90.chs/fxref_mscorlib/html/9f109812-3c14-dcb2-9aff-e18e20dc33ff.htm
  • http://blogs.msdn.com/jb/archive/2006/06/14/631469.aspx  
 
  1. 更多精彩,尽在anytao.net
复制代码
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册