C# · 12月 30, 2021

c# – 最简单的方法是将代码注入到所有没有自定义属性的方法和属性中

.NET在 .NET这里有很多问题和答案在Stack Overflow上,经常提到PostSharp和其他第三方产品.所以在.NET和C#世界中似乎有相当多的AOP optons.但是每一个都有他们的限制,在下载了有希望的PostSharp之后,我在他们的文档中发现,“方法必须是虚拟的”,以便能够注入代码(编辑:见ChrisWue的答案和我的评论 – 虚拟约束必须有曾经在其中一个竞争者,我想).我没有进一步调查这个陈述的准确性,但是它的分类使我回到堆栈溢出.

所以我想得到一个这个非常具体的问题的答案:

我想为我的项目中没有自定义的每个方法和属性(静态,密封,内部,虚拟,非虚拟,无关紧要)注入简单的“(一些条件)Console.WriteLine”样式代码注释,以便在运行时动态测试我的软件.这个注入的代码不应该保留在发行版中,它只是用于在开发过程中进行动态测试(线程相关的).

最简单的方法是什么?我偶然发现了Mono.Cecil,看起来很理想,除了你似乎必须编写你想注入IL的代码.这不是一个巨大的问题,很容易使用Mono.Cecil获取用C#编写的IL版本的代码.但是,如果有一些简单的东西,最好甚至内置到.NET(我仍然在.NET 3.5),我想知道. [更新:如果建议的工具不是.NET Framework的一部分,那么如果是开源的,如Mono.Cecil或免费提供的)

解决方法 我能够解决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 patchassemblyResolver.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;}

如果有人知道如何完成这项工作,我仍然对此感兴趣,我将不会将其作为解决方案,除非没有更简单的解决方案.