我是面向方面编程思想的新手,但我想探索在我的项目中使用它来处理日志记录,报告等的想法.为此,我有一些问题:
我是否应该为这些有限的目的探索这条AOP之路呢?
什么.NET框架支持AOP可用?
哪些框架支持流畅的界面(我讨厌XML配置):)
Henrik.. 23
面向方面编程不仅仅是记录,报告等,您将看到如果您查看PostSharp的网站.就个人而言,我没有做过如此多的静态IL编织,大多是动态IL生成来创建AOP拦截器,当这样做时,我大多数时候一直使用它来包装和拦截来自控制容器反转的结果.
AOP可以改进异常处理,改进跟踪,改善事务拦截.
例如,NHibernate有一种AOP,即使它在简单的事件处理程序方面在编译时是静态的; 但对于引擎中的某些事件,您可以附加拦截器(也就是方面,事件是切入点等) - 我使用它来注入,使用IoC业务实体到我的域对象中.
强大的AOP框架允许您进行概括,甚至更强大,允许您在运行时推广无开销; 原则上你有几种不同的方法:
(0).(不是真的)"预处理器"AOP aka C++中的模板,ifdefs等
反思"AOP"
通过Reflection.Emit在运行时生成IL,需要高度信任.这是Castle项目中的DynamicProxy2路径.DynamicProxy2相当不错,很多工作都进入了它!此外,afaik PatternsAndPractices Policy Framework也使用这种方法,虽然有自己的生成器,但有很多XML.NHibernate依赖于DynProx2.
在运行时通过使用System.CodeDom.Compiler进行IL-compilation + Assembly.Load(...),然后加载创建的程序集,需要高度信任.使用任何其他编译器(如Boo.Compiler)进行编译也是可能的,因为它创建了"全局函数程序集",您可以以"脚本化"方式调用它,但现在我们正在逐渐退出AOP.
Profiler API(不要问我这些)
依赖于运行时框架:扩展MarshalByRef/ContextBoundObject,请参阅链接并使用.Net中的远程处理基础结构来执行AOP,这非常复杂并且会引入您可能不需要的依赖项.
后编译静态IL编织,PostSharp和Mono.Cecil有一个等效的Reflection.Emit,但这个没有错误的具体子类中的虚拟方法调用(如果我没记错的话),如Reflection.Emit,并将很乐意检查您的代码类似于Assembly.ReflectionOnlyLoad,并且还允许您将IL操作输出到该代码中.如果你正在寻找一种相当低级的方法,这是一个很好的选择; 不需要高度信任.
通过p/invoke在托管代码中添加扩展点,以便对C/C++进行非托管回调,但这需要一些思考,因为异常不会愉快地跨越m/um内存边界(相反,它会使应用程序混乱),除非你在Windows中使用VC++/C#和托管异常框架,这可能会非常严重.你可以将回调传递给C和p /从C#调用C,并且可能将回调从C传递到C#,只要你在C#中定义委托即可.扩展点可能必须通过静态或动态IL-weaver +切割来完成.
交易中的用法 查看Castle.Facilities.AutomaticTransactionManagement.TransactionFacility,了解使用AOP处理事务的好方法以及DynamicProxy2的拦截功能.与System.Transcations和System.EnterpriseServices集成的事务工具是使用分布式事务协调器(COM组件)来管理事务.此外,有多个p/invoke进入内核以处理Vista内核(也称为Server 2008)的TxF和TxR组件的例子,它们允许你在NTFS和注册表上使用事务,从而确保CRUD你do是ACID,它也很好地与System.Transactions集成以创建嵌套事务.
不变验证中的用法 您还可以通过在参数中附加一些属性来按合同使用它们进行设计.
public void PerformOperation([NotNull, NotEmpty] string value) { // use string [NotNull] return new string(' ', 5); // can return with attributes as well }
目前的问题是附加这个元数据并在运行时检查它的开销.但是,您可以指定约束检查方面仅在您使用DEBUG进行编译时应用,然后此元数据不会导致性能下降.
如果你想进入公理证明,请看看Sing#/ Spec#,因为那是更正式的,而且工作是由编译器完成的.
需要注意的事项需要注意的 最重要的一点是,如果一个问题,即在您的方法之前或之后运行的某些代码正在改变控制流,可能返回意外类型,过早返回或一般不按照您调用的方法的意图行事可能会得到难以调试的错误.
另外,要注意从属性中抛出异常,因为你永远不知道什么时候或从哪个汇编,反射发生; 你期望的对你的属性的反思可能不会发生.当我在属性中附加类型并仔细检查它们时,这发生在我自己身上.
还要注意这样一个事实,即你在添加全局"切入点"时打开了一个可能的攻击向量,如果有人访问它,可以用来重定向系统的大部分.
其他框架 如果你有兴趣了解更多有关AOP一般我建议你看看里卡德奥伯格对演示Qi4J,它是一个Java AOP的一个非常好的框架(Java有稍微不同的继承对象的语义,虽然这使得凌晨一点小技巧就无论如何使用C#/ F#/ Nermle/Boo.
AOP + AddIns 使用面向方面编程与运行时生成的程序集(例如dynamicproxy2创建)的另一个有趣的可能性是,您还可以使用它们来包装跨越应用程序边界的对象,从而简化了加载项管道的创建.我暗地希望微软在创建3.5的AddIn-framework时会使用它,但不幸的是他们选择了静态代码方式,这为开发人员创建加载项带来了相当大的开销.问题是,除非卸载完整的AppDomain,否则无法再次卸载为"超过反射"加载到AppDomain中的类型
使用AOP进行全局垃圾收集 ...在公共语言基础结构上的linux/windows上运行的分布式系统中.这篇论文有点难以下载,所以我将它上传到我的服务器,所以我知道它在哪里.
Post Scriptum (如果你在CLR上使用非标准语言而不是DLR IL编织可能会创建不符合标准的代码.我认为对F#特别有趣,因为使用了很多非标准代码来实现语言的好处(元组说) - 你可以用[assembly:CLSCompliant]标记你的程序集,如果你想得到这个的编译时警告.)
面向方面编程不仅仅是记录,报告等,您将看到如果您查看PostSharp的网站.就个人而言,我没有做过如此多的静态IL编织,大多是动态IL生成来创建AOP拦截器,当这样做时,我大多数时候一直使用它来包装和拦截来自控制容器反转的结果.
AOP可以改进异常处理,改进跟踪,改善事务拦截.
例如,NHibernate有一种AOP,即使它在简单的事件处理程序方面在编译时是静态的; 但对于引擎中的某些事件,您可以附加拦截器(也就是方面,事件是切入点等) - 我使用它来注入,使用IoC业务实体到我的域对象中.
强大的AOP框架允许您进行概括,甚至更强大,允许您在运行时推广无开销; 原则上你有几种不同的方法:
(0).(不是真的)"预处理器"AOP aka C++中的模板,ifdefs等
反思"AOP"
通过Reflection.Emit在运行时生成IL,需要高度信任.这是Castle项目中的DynamicProxy2路径.DynamicProxy2相当不错,很多工作都进入了它!此外,afaik PatternsAndPractices Policy Framework也使用这种方法,虽然有自己的生成器,但有很多XML.NHibernate依赖于DynProx2.
在运行时通过使用System.CodeDom.Compiler进行IL-compilation + Assembly.Load(...),然后加载创建的程序集,需要高度信任.使用任何其他编译器(如Boo.Compiler)进行编译也是可能的,因为它创建了"全局函数程序集",您可以以"脚本化"方式调用它,但现在我们正在逐渐退出AOP.
Profiler API(不要问我这些)
依赖于运行时框架:扩展MarshalByRef/ContextBoundObject,请参阅链接并使用.Net中的远程处理基础结构来执行AOP,这非常复杂并且会引入您可能不需要的依赖项.
后编译静态IL编织,PostSharp和Mono.Cecil有一个等效的Reflection.Emit,但这个没有错误的具体子类中的虚拟方法调用(如果我没记错的话),如Reflection.Emit,并将很乐意检查您的代码类似于Assembly.ReflectionOnlyLoad,并且还允许您将IL操作输出到该代码中.如果你正在寻找一种相当低级的方法,这是一个很好的选择; 不需要高度信任.
通过p/invoke在托管代码中添加扩展点,以便对C/C++进行非托管回调,但这需要一些思考,因为异常不会愉快地跨越m/um内存边界(相反,它会使应用程序混乱),除非你在Windows中使用VC++/C#和托管异常框架,这可能会非常严重.你可以将回调传递给C和p /从C#调用C,并且可能将回调从C传递到C#,只要你在C#中定义委托即可.扩展点可能必须通过静态或动态IL-weaver +切割来完成.
交易中的用法 查看Castle.Facilities.AutomaticTransactionManagement.TransactionFacility,了解使用AOP处理事务的好方法以及DynamicProxy2的拦截功能.与System.Transcations和System.EnterpriseServices集成的事务工具是使用分布式事务协调器(COM组件)来管理事务.此外,有多个p/invoke进入内核以处理Vista内核(也称为Server 2008)的TxF和TxR组件的例子,它们允许你在NTFS和注册表上使用事务,从而确保CRUD你do是ACID,它也很好地与System.Transactions集成以创建嵌套事务.
不变验证中的用法 您还可以通过在参数中附加一些属性来按合同使用它们进行设计.
public void PerformOperation([NotNull, NotEmpty] string value) { // use string [NotNull] return new string(' ', 5); // can return with attributes as well }
目前的问题是附加这个元数据并在运行时检查它的开销.但是,您可以指定约束检查方面仅在您使用DEBUG进行编译时应用,然后此元数据不会导致性能下降.
如果你想进入公理证明,请看看Sing#/ Spec#,因为那是更正式的,而且工作是由编译器完成的.
需要注意的事项需要注意的 最重要的一点是,如果一个问题,即在您的方法之前或之后运行的某些代码正在改变控制流,可能返回意外类型,过早返回或一般不按照您调用的方法的意图行事可能会得到难以调试的错误.
另外,要注意从属性中抛出异常,因为你永远不知道什么时候或从哪个汇编,反射发生; 你期望的对你的属性的反思可能不会发生.当我在属性中附加类型并仔细检查它们时,这发生在我自己身上.
还要注意这样一个事实,即你在添加全局"切入点"时打开了一个可能的攻击向量,如果有人访问它,可以用来重定向系统的大部分.
其他框架 如果你有兴趣了解更多有关AOP一般我建议你看看里卡德奥伯格对演示Qi4J,它是一个Java AOP的一个非常好的框架(Java有稍微不同的继承对象的语义,虽然这使得凌晨一点小技巧就无论如何使用C#/ F#/ Nermle/Boo.
AOP + AddIns 使用面向方面编程与运行时生成的程序集(例如dynamicproxy2创建)的另一个有趣的可能性是,您还可以使用它们来包装跨越应用程序边界的对象,从而简化了加载项管道的创建.我暗地希望微软在创建3.5的AddIn-framework时会使用它,但不幸的是他们选择了静态代码方式,这为开发人员创建加载项带来了相当大的开销.问题是,除非卸载完整的AppDomain,否则无法再次卸载为"超过反射"加载到AppDomain中的类型
使用AOP进行全局垃圾收集 ...在公共语言基础结构上的linux/windows上运行的分布式系统中.这篇论文有点难以下载,所以我将它上传到我的服务器,所以我知道它在哪里.
Post Scriptum (如果你在CLR上使用非标准语言而不是DLR IL编织可能会创建不符合标准的代码.我认为对F#特别有趣,因为使用了很多非标准代码来实现语言的好处(元组说) - 你可以用[assembly:CLSCompliant]标记你的程序集,如果你想得到这个的编译时警告.)