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

前端之家收集整理的这篇文章主要介绍了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 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;
}

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

猜你在找的C#相关文章