MSBuild + MSILInect实现编译时AOP之预览

简介:

      在本文之前的前几篇浅谈.NET编译时注入(C#-->IL浅谈VS编译自定义编译任务—MSBuild Task(csproject)编译时MSIL注入--实践Mono Cecil(1)已经讨论了MSBuild和Mono.Cicel。在这里我们将会利用它来实现一个简单的编译时AOP注入机制(这里所说的编译时是指c#到MSIL的预编译过程)。我更倾向于像EL(微软企业库框架)这类动态AOP。编译时AOP有PostSharp这种被称之为静态AOP框架,其优势在于直接代码语句,性能更好,它不需要我们多余的代码,像EL这种动态AOP,一般我们是不能直接new一个对象,需要容器(Container),在一些你的框架应用种,有时就需要使用者了解,再入我们对于WinForm、WebForm等.net平台上主流的基于微软事件机制的框架,事件方法的截获,往往我们需要改变、包装。在这时静态AOP就显出了他的优势。

Class Diagram

1IMethodInjectInterface,拥有ExecuteingExceptionedExecuteSuccess三个契约为别为执行前,异常,成功。它们都有公同的参数类型:MethodExecutionEventArgs


 

    Executeing:返回值为bool类型,将决定是否继续执行方法体。Exceptioned:属性Eeption代表发生的异常信息,返回值ExceptionStrategy(取值:Handle, ReThrow, ThrowNew)决定异常处理机制,Handle已处理并忽略,ReThrow重新抛出,ThrowNew抛出一个包装后的来源于MethodExecutionEventArgs 的Exception。ExecuteSuccess,对于拥有返回值的方法,可以修改MethodExecutionEventArgs 的ReturnValue,修改返回值。最后MethodExecutionEventArgs的Order决定多个Attribute的注入先后,即方法截获的先后顺序。

1:MethodInterceptBase针对于方法Attribute标签,实现方法截获

ExpandedBlockStart.gif
复制代码
[AttributeUsage(AttributeTargets.Method, Inherited  =   false , AllowMultiple  =   false )]
    
public   class  MethodInterceptBase : Attribute, IMethodInject
    {
        
public   int  Order
        {
            
get ;
            
set ;
        }
        
#region  IMethodInject Members

        
public   virtual   bool  Executeing(MethodExecutionEventArgs args)
        {
            
return   true ;
        }

        
public   virtual  ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)
        {
            
return  ExceptionStrategy.ReThrow;
        }

        
public   virtual   void  ExecuteSuccess(MethodExecutionEventArgs args)
        {

        }
       
        
#endregion
}
复制代码

2MatchedMethodInterceptBase和上面方法之上的MethodInterceptBase大体一致,区别在于其应用于class之上,属性Rule为截获方法匹配(应用于多个方法之上相同截获),支持*匹配。

ExpandedBlockStart.gif
复制代码
 
[AttributeUsage(AttributeTargets.Class, Inherited  =   false , AllowMultiple  =   false )]

    
public   class  MatchedMethodInterceptBase : Attribute, IMethodInject

    {

        
public   int  Order

        {

            
get ;

            
set ;

        }

 

        
public   string  Rule

        {

            
get ;

            
set ;

        }

        
#region  IMethodInject Members


        
public   virtual   bool  Executeing(MethodExecutionEventArgs args)

        {

            
return   true ;

        }
 

        
public   virtual  ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)

        {

            
return  ExceptionStrategy.ReThrow;

        }

 

        
public   virtual   void  ExecuteSuccess(MethodExecutionEventArgs args)

        {

 

        }

       

        
#endregion

    }
复制代码

3PropertyInterceptBase实现属性的注入,其属性Actionenum PropertyInterceptActionNone Get, Set)指注入属性的get或者Set 
ExpandedBlockStart.gif
复制代码
 
[AttributeUsage(AttributeTargets.Property, Inherited  =   false , AllowMultiple  =   false )]
    
public   class  PropertyInterceptBase : Attribute, IMethodInject
    {
        
public  PropertyInterceptAction Action
        {
            
get ;
            
set ;
        }

        
public   int  Order
        {
            
get ;
            
set ;
        }
        
#region  IMethodInject Members

        
public   virtual   bool  Executeing(MethodExecutionEventArgs args)
        {
            
return   true ;
        }

        
public   virtual  ExceptionStrategy Exceptioned(MethodExecutionEventArgs args)
        {
            
return  ExceptionStrategy.ReThrow;
        }

        
public   virtual   void  ExecuteSuccess(MethodExecutionEventArgs args)
        {

        }

        
#endregion
    }
复制代码

其上默认都是Executeing继续执行,Exceptioned为抛出不处理,成功不修改result。

下面是一个简单测试Code:

ExpandedBlockStart.gif
复制代码
using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

using  System.Reflection;

using  Green.AOP;

 

namespace  Test

{   

    
//  [TestAOP2Attribute(Rule = "TestMethod1*")]

    
public   class  Class1

    {

        
//  [TestAOPPropertyAttribute(Action = PropertyInterceptAction.Set)]

        [TestAOPPropertyGetAttribute(Action 
=  PropertyInterceptAction.Get)]

        
public  testStrust TestProperty

        {

            
get ;

            
set ;

        }

        [Obsolete()]

        
public   static   void  Main( string [] args)

        {          

            
try

            {

                var y 
=   new  Class1();

                
//  y.TestProperty = DateTime.Now;

                Console.WriteLine(y.TestProperty);

            }

            
catch  (Exception ex)

            {

                Console.WriteLine(ex.ToString());

            }

            
//  new Class1().TestMethod1(1, 2, null);

            Console.Read();

            
// throw new Exception("exfffffffffffffffffffff");

        }

        
// [TestAOPAttribute(Order=1)]

        
// [TestAOP1Attribute(TestProperty = 1, Template = "sdsdsd",Order=0)]

        
public  Class1 TestMethod1( int  i,  int  j, Class1 c)

        {

            Console.WriteLine(
" ok " );

            
return   new  Class1();

        }

    }

    
public   class  TestAOPPropertyGetAttribute : Green.AOP.PropertyInterceptBase

    {

        
#region  IMethodInject Members

        
public   override   bool  Executeing(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
" ------------------ "   +  args);

            Console.WriteLine(args.Instance);

            Console.WriteLine(args.Method);

            Console.WriteLine(
this .GetType()  +   " : "   +   " Executeing " );

            
return   true ;

        }

        
public   override  Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Exceptioned " );

            
return  Green.AOP.ExceptionStrategy.ReThrow;

        }

        
public   override   void  ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
" ----------- " );

            Console.WriteLine(
this .GetType()  +   " : "   +   " ExecuteSuccess "   +   " --result: "   +  args.ReturnValue);

        }

        
#endregion

    }

    
public   class  TestAOPPropertyAttribute : Green.AOP.PropertyInterceptBase

    {

        
#region  IMethodInject Members

        
public   override   bool  Executeing(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(args.Instance);

            Console.WriteLine(args.Method);

            Console.WriteLine(
this .GetType()  +   " : "   +   " Executeing " );

            
return   true ;

        }

        
public   override  Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Exceptioned " );

            
return  Green.AOP.ExceptionStrategy.Handle;

        }

        
public   override   void  ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

       {

            Console.WriteLine(
this .GetType()  +   " : "   +   " ExecuteSuccess " );

        }

        
#endregion

    }

    
public   class  TestAOP2Attribute : Green.AOP.MatchedMethodInterceptBase

    {

        
#region  IMethodInject Members

        
public   override   bool  Executeing(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(args.Instance);

            Console.WriteLine(args.Method);

            Console.WriteLine(
this .GetType()  +   " : "   +   " Executeing " );

            
return   true ;

        }

        
public   override  Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Exceptioned " );

            
return  Green.AOP.ExceptionStrategy.Handle;

        }

        
public   override   void  ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " ExecuteSuccess " );

        }

        
#endregion

        
#region  IMethodInject Members

        
public   bool  Match(System.Reflection.MethodBase method)

        {

            
return   true ;

        }

        
#endregion

    }

 

    
// [AttributeUsage(AttributeTargets.Method)]

    
public   class  TestAOPAttribute : Green.AOP.MethodInterceptBase

    {

        
#region  IMethodInject Members

        
public   override   bool  Executeing(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Executeing " );

            
return   true ;

        }

 

        
public   override  Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Exceptioned " );

            
return  Green.AOP.ExceptionStrategy.Handle;

        }

 

        
public   override   void  ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " ExecuteSuccess " );

        }

 

        
#endregion

 

        
#region  IMethodInject Members

 

 

        
public   bool  Match(System.Reflection.MethodBase method)

        {

            
return   true ;

        }

 

        
#endregion

    }

 

    [AttributeUsage(AttributeTargets.Method)]

    
public   class  TestAOP1Attribute : Attribute, Green.AOP.IMethodInject

    {

        
public   int  Order

        {

            
get ;

            
set ;

        }

 

        
public   int  TestProperty

        {

            
get ;

            
set ;

        }

 

        
public   string  Template

        {

            
get ;

            
set ;

        }

 

        
#region  IMethodInject Members

 

        
public   bool  Executeing(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Executeing " );

            
return   true ;

        }

 

        
public  Green.AOP.ExceptionStrategy Exceptioned(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " Exceptioned " );

            
return  Green.AOP.ExceptionStrategy.Handle;

        }

 

        
public   void  ExecuteSuccess(Green.AOP.MethodExecutionEventArgs args)

        {

            Console.WriteLine(
this .GetType()  +   " : "   +   " ExecuteSuccess " );

        }

 

        
#endregion

 

        
#region  IMethodInject Members

 

 

        
public   bool  Match(System.Reflection.MethodBase method)

        {

            
return   true ;

        }

 

        
#endregion

    }

 

}
复制代码

 注意测试有两种方式(由于没有安装包):

1:先重编译测试项目,运行ConsoleApplication2(在属性中修改控制台其实参数)。在查看测试项目。

2:将项目ConsoleApplication2修改为类库,在添加修改csprojec信息,Task位于Green.AOP.MyBuildTask,具体可以参见上一篇浅谈VS编译自定义编译任务—MSBuild Task(csproject)

在后续将会从简单Demo分析实现原理。

 


作者:破  狼 
出处:http://www.cnblogs.com/whitewolf/ 
本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。该文章也同时发布在我的独立博客中-个人独立博客博客园--破狼51CTO--破狼。http://www.cnblogs.com/whitewolf/archive/2011/08/09/2132217.html

相关文章
|
Java Android开发
【AOP 面向切面编程】Android Studio 中配置 AspectJ ( 下载并配置AS中 jar 包 | 配置 Gradle 和 Gradle 插件版本 | 配置 Gradle 构建脚本 )(一)
【AOP 面向切面编程】Android Studio 中配置 AspectJ ( 下载并配置AS中 jar 包 | 配置 Gradle 和 Gradle 插件版本 | 配置 Gradle 构建脚本 )(一)
428 0
【AOP 面向切面编程】Android Studio 中配置 AspectJ ( 下载并配置AS中 jar 包 | 配置 Gradle 和 Gradle 插件版本 | 配置 Gradle 构建脚本 )(一)
|
Java Android开发
编译安卓项目时报错
编译安卓项目时报错
325 0
编译安卓项目时报错
|
vr&ar 图形学
【100个 Unity小知识点】☀️ | Unity 可以在编辑器中读取Excel,打包成exe后就无法读取的问题
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。 也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
|
XML Java Android开发
Unity是怎么打包APK文件的
大家看过一些第三方组件的接入文档都知道,在Unity里面有几个特殊的文件夹是跟打包APK有关的。首先我们就来了解一下,这些文件夹里面的内容是经历了哪些操作才被放到APK里面的呢? 在Unity的Assets目录下,Plugins/Android无疑是其中的重中之重,首先我们先来看一个常见的Plugins/Android目录是什么样子的。
5097 0
|
API C# C++
C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件
原文:C#开发奇技淫巧二:根据dll文件加载C++或者Delphi插件       这两天忙着把框架改为支持加载C++和Delphi的插件,来不及更新blog了。      原来的写的框架只支持c#插件,这个好做,直接用c#的反射功能便可。
1064 0
|
XML C# 图形学
Unity 使用VisualStuido将C#脚本封装打包DLL使用
为了方便开发,不破坏写好工具的封装性,我们经常讲C#脚本打包成DLL使用,操作流程如下 创建项目,注意选择Net Framework版本,过高Unity无法支持 添加在脚本中使用的unity引用,在封装的脚本中我只使用了UnityEngine.
1994 0