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

问题的提出 

晚上翻着群里的聊天,发现一个有趣的问题:如何通过编码方式来判断一个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 DEBUGConsole.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 > 0 ? attributes[0] 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 nameAssembly ass = Assembly.LoadFile(assemblyName);// Get DebuggableAttribute infoDebuggableAttribute 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(){// Arrangestring ass1 = @"D:\debugass.exe";string ass2 = @"D:\releaseass.exe";// Act string mode1 = AnyContext.GetDebugMode(ass1).ToString();string mode2 = AnyContext.GetDebugMode(ass2).ToString();// AssetAssert.AreEqual(mode1, "Debug");Assert.AreEqual(mode2, "Release");}
}

一切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  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/438677.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

执行本地sql_实用!5个在线 SQL 数据库环境

文章目录SQL FiddleDB Fiddledb<>fiddleSQL OnlineOracle Live SQL总结大今天给大家分享几个在线的免费 SQL 运行环境&#xff0c;也就是在线数据库。这些网站可以帮助我们快速运行一些 SQL 语句的测试或者验证&#xff0c;同时还可以在网络上进行分享&#xff0c;关键不…

ocp证书怎么考_没有基础怎么考初级会计证书?

初级会计证书这些年来越发火热&#xff0c;报考门槛也较低。多数报考初级会计证的考生都是没有基础的&#xff0c;那么怎么复习呢?今天会计网将给大家带来没有基础怎么考初级会计证书?1、制定一份适合自己的学习计划&#xff0c;分阶段学习对于没有基础的考生而言&#xff0c…

与gps优缺点_长缨在手,敢缚苍龙,中国北斗三号圆满收官,相比美国GPS怎样?...

2020年6月23日&#xff0c;北斗三号最后一颗全球组网卫星发射成功&#xff0c;完美收官。我们都知道信息化时代定位导航的重要性&#xff0c;那么中国北斗和美国GPS相对比怎么样呢&#xff1f;首先来了解一下北斗。中国的北斗导航系统是分三步建设的。卫星导航系统第一步在1994…

11单件模式(Singleton Pattern)

创建型模式---单件模式(Singleton Pattern)动机&#xff08;Motivation): 在软件系统中&#xff0c;经常有这样一些特殊的类&#xff0c;必须保证它们在系统中只存在一个实例&#xff0c;才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器&#xff0c;…

查找字符位置_如何使用find函数和search函数精确查找字符

精确查找指定字符在一个字符串中的位置是Excel函数运用中的一项重要的技巧&#xff0c;尤其是在截取字符串、替换字符串等文本处理过程中&#xff0c;精确定位技术更是必不可少。查找字符的主要函数是find函数和search函数&#xff0c;两者的语法完全相同。find(find_text,with…

12抽象工厂(Abstract Factory)

常规的对象创建方法&#xff1a; //创建一个Road对象 Road road new Road(); new 的问题&#xff1a; 实现依赖&#xff0c;不能应对“具体实例化类型”的变化。解决思路&#xff1a; 封装变化点-----哪里变化&#xff0c;封装哪里 潜台词&#xff1a; 如果没有变…

13建造者模式(Builder)

Builder模式的缘起&#xff1a; 假设创建游戏中的一个房屋House设施&#xff0c;该房屋的构建由几部分组成&#xff0c;且各个部分富于变化。如果使用最直观的设计方法&#xff0c;每一个房屋部分的变化&#xff0c;都将导致房屋构建的重新修正.....动机&#xff08;Motiva…

15原型模式(Prototype)

依赖关系倒置&#xff1a; 动机(Motivate): 在软件系统中&#xff0c;经常面临着“某些结构复杂的对象”的创建工作;由于需求的变化&#xff0c;这些对象经常面临着剧烈的变化,但是它们却拥有比较稳定一致的接口。 如何应对这种变化&#xff1f;如何向“客户…

14工厂方法模式(Factory Method)

耦合关系&#xff1a; 动机(Motivation): 在软件系统中&#xff0c;由于需求的变化&#xff0c;"这个对象的具体实现"经常面临着剧烈的变化&#xff0c;但它却有比较稳定的接口。 如何应对这种变化呢&#xff1f;提供一种封装机制来隔离出"这个易…

mysql 更新错误1062_mysql 出现1062错误怎么办

mysql 出现1062错误的解决办法&#xff1a;首先打开mysql的配置文件【my.cnf】&#xff1b;然后在client和mysqld下面加上相关代码&#xff1b;最后存关闭后重启mysql即可。mysql 出现1062错误的解决办法&#xff1a;两个instance的版本接近&#xff0c;猜测不是版本问题。执行…

21适配器模式(Adapter Pattern)

适配&#xff08;转换&#xff09;的概念无处不在...... 适配&#xff0c;即在不改变原有实现的基础上&#xff0c;将原先不兼容的接口转换为兼容的接口。 例如&#xff1a;二转换为三箱插头&#xff0c;将高电压转换为低电压等。 动机(Motivate): 在软件系统中&#…

22桥接模式(Bridge Pattern)

动机(Motivate): 在软件系统中&#xff0c;某些类型由于自身的逻辑&#xff0c;它具有两个或多个维度的变化&#xff0c;那么如何应对这种“多维度的变化”&#xff1f;如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化&#xff0c;而又不引入额外的复杂度…

mysql动静分离_haproxy的web服务负载均衡、动静分离、 MySQL服务负载均衡、状态监控...

实验环境&#xff1a;基于centos6.6haproxy-Server&#xff1a;172.16.249.98 hostname:node1upsteram server1&#xff1a;172.16.249.100 hostname:node2upstream server2&#xff1a;172.16.249.99 hostname:node3web服务的负载均衡以及状态监控&#xff1a;设置记录hapro…

24组合模式(Composite Pattern)

动机(Motivate): 组合模式有时候又叫做部分-整体模式&#xff0c;它使我们树型结构的问题中&#xff0c;模糊了简单元素和复杂元素的概念&#xff0c;客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。意图(Intent): 将对象组合…

23装饰模式(Decorator Pattern)

子类复子类&#xff0c;子类何其多 假如我们需要为游戏中开发一种坦克&#xff0c;除了各种不同型号的坦克外&#xff0c;我们还希望在不同场合中为其增加以下一种或多种功能;比如红外线夜视功能&#xff0c;比如水陆两栖功能&#xff0c;比如卫星定位功能等等。 按类继承的作法…

gb2312编码在线转换_python基础学习—04字符串与编码

点击上方蓝字关注我们不迷路&#xff01;字符串与编码一、了解计算机编码1.1 编码定义&#xff1a;将信息从一种形式转换为另外一种形式的过程叫做编码&#xff0c;即信息转换过程举例&#xff1a;信息加密解密、语言翻译1.2 计算机编码定义&#xff1a;将计算机可读信息转换…

25外观模式(Facade Pattern)

动机(Motivate): 在软件开发系统中&#xff0c;客户程序经常会与复杂系统的内部子系统之间产生耦合&#xff0c;而导致客户程序随着子系统的变化而变化。那么如何简化客户程序与子系统之间的交互接口&#xff1f;如何将复杂系统的内部子系统与客户程序之间的依赖解耦&#…

mysql mybatis类型对应_Mybatis与数据库的类型对应

Mybatis与数据库的类型对应由于业务的改变&#xff0c;在首次存入数据库时某些int属性并没有赋值&#xff0c;于是默认值就开始污染数据库了。java实体属性对应mysql和SQL Server 和Oracle 数据类型对应1&#xff1a;Java数据类型与MySql数据类型对照表*对于bolb&#xff0c;一…

26享元模式(Flyweight Pattern)

面向对象的代价 面向对象很好地解决了系统抽象性的问题&#xff0c;同时在大多数情况下&#xff0c;也不会损及系统的性能。但是&#xff0c;在 某些特殊的应用中下&#xff0c;由于对象的数量太大&#xff0c;采用面向对象会给系统带来难以承受的内存开销。比如: 图形应用…

mysql一个事务多个log_MySQL识别一个binlog中的一个事物

MySQL测试版本5.7.14设置GTID_MODEONON(3): Both new and replicated transactions must be GTID transactions(生成的是GTID事物&#xff0c;slave也只能应用GTID事物)设置binlog格式为row模式做如下操作mysql> insert into test values(1,2);Query OK, 1 row affected (0.…