所以我想得到一个这个非常具体的问题的答案:
我想为我的项目中没有自定义的每个方法和属性(静态,密封,内部,虚拟,非虚拟,无关紧要)注入简单的“(一些条件)Console.WriteLine”样式代码注释,以便在运行时动态测试我的软件.这个注入的代码不应该保留在发行版中,它只是用于在开发过程中进行动态测试(线程相关的).
最简单的方法是什么?我偶然发现了Mono.Cecil,看起来很理想,除了你似乎必须编写你想注入IL的代码.这不是一个巨大的问题,很容易使用Mono.Cecil获取用C#编写的IL版本的代码.但是,如果有一些简单的东西,最好甚至内置到.NET(我仍然在.NET 3.5),我想知道. [更新:如果建议的工具不是.NET Framework的一部分,那么如果是开源的,如Mono.Cecil或免费提供的)
解决方法
这些是我使用的3种文件来源:
> static-method-interception-in-net-with-c-and-monocecil
> Migration to 0.9
>源代码本身
第一个链接提供了一个非常温和的介绍,但是它描述了一个较旧版本的Cecil – 并且在很大程度上已经改变了 – 第二个链接是非常有帮助的翻译Cecil 0.9的介绍.开始之后,(也没有记录)的源代码是非常宝贵的,并回答了我所有的每一个问题 – 也许有一些关于.NET平台的一般问题,但是我在网上有很多书籍和材料.
我现在可以使用DLL或EXE文件,修改它,并将其写回磁盘.我还没有做的唯一的事情是弄清楚如何保存调试信息 – 文件名,行号等,在编写DLL或EXE文件之后,现在会丢失.我的背景不是.NET,所以我猜这里,我的猜测是,我需要看mono.cecil.pdb来修复.在某个地方 – 现在对我而言并不重要.我正在创建这个EXE文件,运行应用程序 – 它是一个复杂的GUI应用程序,多年来一直在使用所有行李,你会发现在这样一块,ahem的软件 – 它检查事情和日志错误我.
这是我的代码的要点:
DefaultAssemblyResolver assemblyResolver = new DefaultAssemblyResolver(); // so it won't complain about not finding assemblies sitting in the same directory as the dll/exe we are going to patch assemblyResolver.AddSearchDirectory(assemblyDirectory); var readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver }; AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyFilename,readerParameters); foreach (var moduleDefinition in assembly.Modules) { foreach (var type in ModuleDefinitionRocks.GetAllTypes(moduleDefinition)) { foreach (var method in type.Methods) { if (!HasAttribute("MyCustomAttribute",method.method.CustomAttributes) { ILProcessor ilProcessor = method.Body.GetILProcessor(); ilProcessor.InsertBefore(method.Body.Instructions.First(),ilProcessor.Create(OpCodes.Call,threadCheckerMethod)); // ... private static bool HasAttribute(string attributeName,IEnumerable<CustomAttribute> customAttributes) { return GetAttributeByName(attributeName,customAttributes) != null; } private static CustomAttribute GetAttributeByName(string attributeName,IEnumerable<CustomAttribute> customAttributes) { foreach (var attribute in customAttributes) if (attribute.AttributeType.FullName == attributeName) return attribute; return null; }