发布日期: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模式下,该预编译将被省略。例如如果执行:
#if DEBUG

    Console.WriteLine("Hi");

#endif

在Debug模式下,Console.WriteLine(“Hi”)将参与编译,而Release模式下,会忽略该语句的执行。不过,如果你手动添加

#define DEBUG

在两种模式下,都会执行Console.WriteLine(“Hi”)的编译。究其原因,是Visual Studio在默认情况下预定义了#define DEBUG,我们可以通过开关来设置:

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

解决方案

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

那么,我们开始吧。

构建

首先我们创建一个AnyContext来承载通用的上下文服务,在这里主要包含的就是:

/// <summary>
/// A common context
/// </summary>
/// <remarks>
/// Anytao, http://www.anytao.com
/// </remarks>
public class AnyContext : IAnyObject
{
public static DebugMode GetDebugMode(string assemblyName)
{
}
}
其中,DebugMode是一个简单的枚举:
/// <summary>
/// Debug mode type
/// </summary>
/// <remarks>
/// Anytao, http://www.anytao.com
/// </remarks>
public enum DebugMode
{
Debug,
Release
}

可向而知,我们需要实现一个根据Assembly信息获取DebuggrableAttribute的Helper类,既然是Helper类我们希望能够兼顾各种情况,因此通过泛型方法是做好的选择,具体实现如下:

/// <summary>
/// Common helper
/// </summary>
/// <remarks>
/// Anytao, http://www.anytao.com
/// </remarks>
public static class Utils
{
/// <summary>
/// Get GetCustomAttribute
/// </summary>
/// <typeparam name="T">CustomAttribute Type</typeparam>
/// <param name="provider"></param>
/// <returns></returns>
public static T GetCustomAttribute<T>(this ICustomAttributeProvider provider)
where T : Attribute
{
var attributes = provider.GetCustomAttributes(typeof(T), false); return attributes.Length > ? attributes[] as T : default(T);
}
}

此处的GetCustomAttribute被实现为扩展方法,那么任何实现了ICustomAttributeProvider接口的类型,都可以通过其获取CustomAttribute了,例如:Type、Assembly、Module、MethodInfo,都可以实现对GetCustomAttribute的调用。

接下来,GetDebugMode的逻辑就变得很简单,我们传入assembly路径即可获取DebuggrableAttribute,并由此推导IsJITTrackingEnabled的情况:

public static DebugMode GetDebugMode(string assemblyName)
{
if (string.IsNullOrEmpty(assemblyName))
{
throw new ArgumentNullException("assemblyName");
} DebugMode ret = DebugMode.Debug; try
{
// Get assebly by name
Assembly ass = Assembly.LoadFile(assemblyName); // Get DebuggableAttribute info
DebuggableAttribute att = ass.GetCustomAttribute<DebuggableAttribute>(); ret = att.IsJITTrackingEnabled ? DebugMode.Debug : DebugMode.Release;
}
catch (Exception)
{
throw;
} return ret;
}
好了,这就是一个简单的判断逻辑,在AnyContext中包含了很多诸如此类的上下文定义,而GetDebugMode提供了本文开头的解决方案。

测试

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

    • debugass.exe
    • releaseass.exe
  • 新建TestProject,并对GetDebugMode进行测试如下:
[TestClass]
public class AnyContextTest
{
[TestMethod]
public void TestIsDebugOrRelease()
{
// Arrange
string ass1 = @"D:\debugass.exe";
string ass2 = @"D:\releaseass.exe"; // Act
string mode1 = AnyContext.GetDebugMode(ass1).ToString();
string mode2 = AnyContext.GetDebugMode(ass2).ToString(); // Asset
Assert.AreEqual(mode1, "Debug");
Assert.AreEqual(mode2, "Release");
}
}

一切OK,你不妨试试。

注:本测试在.NET 2.0及其以上版本测试通过,如您有更多精力,可对其以下版本进行分析。

参考文献:

更多精彩,尽在anytao.net

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

  1. [你必须知道的.NET]第三十四回,object成员,不见了!

    发布日期:2009.10.30 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 在.NET世界了,object是公认的造物主,其麾下的7大成员, ...

  2. [你必须知道的.NET]第三十回:.NET十年(下)

    发布日期:2009.05.11 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文部分内容,已 ...

  3. [你必须知道的.NET]第三十二回,,深入.NET 4.0之,Tuple一二

    发布日期:2009.06.01 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. Tuple,是函数式编程的概念之一,早见于Elang.F#等动态 ...

  4. [你必须知道的.NET]第三十一回,深入.NET 4.0之,从“新”展望

    发布日期:2009.05.22 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. /// <summary> /// 本文开始,将以& ...

  5. [你必须知道的.NET]第三十三回,深入.NET 4.0之,Lazy<T>点滴

    发布日期:2009.10.29 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 对象的创建方式,始终代表了软件工业的生产力方向,代表了先进软件技 ...

  6. 你必须知道的.net读书笔记之第二回深入浅出关键字---对抽象编程:接口和抽象类

    请记住,面向对象思想的一个最重要的原则就是:面向接口编程. 借助接口和抽象类,23个设计模式中的很多思想被巧妙的实现了,我认为其精髓简单说来就是:面向抽象编程. 抽象类应主要用于关系密切的对象,而接口 ...

  7. 你必须知道的.net读书笔记第四回:后来居上:class和struct

     基本概念 1.1. 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构类型,通常包含字段.属性.方法.属性.构造函数.索引器.操作符等.因为是基本的概念,所以不必在此 ...

  8. [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理

    原文地址:http://kb.cnblogs.com/page/42318/ 系列文章导航: [你必须知道的.NET] 开篇有益 [你必须知道的.NET] 第一回:恩怨情仇:is和as [你必须知道的 ...

  9. [你必须知道的.NET]第二十五回:认识元数据和IL(中)

    发布日期:2009.02.25 作者:Anytao © 2009 Anytao.com ,Anytao原创作品,转贴请注明作者和出处. 说在,开篇之前 书接上回[第二十四回:认识元数据和IL(上)], ...

随机推荐

  1. Postgres Basic Commands for Beginners

    Just sharing what I have learned about postgres recently. Here is a part of basic commands you may n ...

  2. C++中int *p[4]和 int (*q)[4]的区别

    这俩兄弟长得实在太像,以至于经常让人混淆.然而细心领会和甄别就会发现它们大有不同. 前者是指针数组,后者是指向数组的指针.更详细地说. 前: 指针数组;是一个元素全为指针的数组.后: 数组指针;可以直 ...

  3. poj 1338 Ugly Numbers

    原题链接:http://poj.org/problem?id=1338 优先队列的应用,如下: #include<cstdio> #include<cstdlib> #incl ...

  4. Android 上下文菜单实现

    1.覆盖Activity的onCreateContenxtMenu()方法,调用Menu的add方法添加菜单项(MenuItem). 2.覆盖Activity的onContextItemSelecte ...

  5. c++性能测试

    程序分析是以某种语言书写的程序为对象,对其内部的运作流程进行分析.程序分析的目的主要有三点:一是通过程序内部各个模块之间的调用关系,整体上把握程序的运行流程,从而更好地理解程序,从中汲取有价值的内容. ...

  6. JS中showModalDialog 详细使用

    基本介绍: showModalDialog() (IE 4+ 支持) showModelessDialog() (IE 5+ 支持) window.showModalDialog() 方法用来创建一个 ...

  7. java7新特新(一) Try-with-resources (TWR)

    Try-with-resources (TWR) 在处理IO的代码中,我们会使用大量的try...catch()...finally...语法,其中会在finally进行IO的close操作,写过py ...

  8. panel面板

    描述:作为承载其他内容的容器的,装载其他组件基础,可折叠.关闭.最大化.最小化和自定义行为.面板可以很容易地嵌入到web页面的任何位置. 其他属性请参考api! 案例1:纯html生成 <div ...

  9. 判断js和css是否加载完成

    在通过ajax或者src动态获取js.css文件的时候,我们常常需要判断文件是否加载完成,以便进行进一步的操作,但是在检测js.css文件是否已经加载的策略上各浏览器并不统一,有很多坑,现在在这里总结 ...

  10. ptypes中string类的空间分配

    问题描述:            在学习ptypes中string类的空间分配时,经常使分配的空间超出实际所需的空间 使用的分配函数是:_alloc函数 注:        在_alloc函数中调用了 ...