Aspect# 语言目的是免去在 XML 语法上滚来滚去之苦,提供一个干净的方式配置、识别和书写你的切面配置。
内容索引
1. 基础定义
2. Import 导入
3. 全局拦截机
4. 全局 Mixin 混入
5. 切面 aspect
6. 包含 include
7. 切入点 pointcut
8. 通知 advice
1. 基础定义
在使用 Aspect# 语言时务必遵循一些规则,首要的规则是顺序。因此你的声明务必遵循以下顺序:
[Import 导入][Interceptor 全局拦截机映射]
[Mixin 全局混入映射]
Aspects 切面定义
2. Import 导入
导入区域帮助你保持一个干净的代码环境,并帮助 Aspect 语言解释类的声明。
import 命名空间名称 [in 程序集名称]例如:
import System.Collections in Systemimport AspectSharp.Core
3. 全局拦截机
当你有一个拦截机,准备运用到多个切面,甚或运用到多个切入点的时候,你可以把它定义到全局拦截机区域:
interceptors ["键名1" : 拦截机类A ;
"键名2" : 拦截机类B
]
例如
interceptors ["logger" : DigitalGravity.Interceptors.Logger in DigitalGravity.XProject
]
这是没有导入命名空间的映射声明。
import DigitalGravity.Interceptors in DigitalGravity.XProjectinterceptors [
"logger" : Logger
]
这是已经导入命名空间的映射声明。
当你完成这些后,就可以在一个切面定义中通过关键字 advice 根据『键名』来引用它们:
aspect Test for MyClasspointcut method(*)
advice("key")
end
pointcut property(*)
advice("key2")
end
end
4. 全局混入
同样的理由,我们也需要一个全局混入区域:
mixins ["键名1" : 混入类A ;
"键名2" : 混入类B
]
例如
mixins ["security" : DigitalGravity.Mixins.SecurityMixin in DigitalGravity.XProject
]
这是没有导入命名空间的映射声明。
Import DigitalGravity.Mixins in DigitalGravity.XProjectmixins [
"security" : SecurityMixin
]
这是已经导入命名空间的映射声明。
当你完成这些后,就可以在一个切面定义中通过 include 关键字并根据『键名』来引用它们:
aspect Test for MyClassinclude("security")
end
注意,mixin 混入使用的是 include 引用,而拦截机使用的是 advice 引用。
5. 切面 aspect
一个切面区域用来定义哪些混入 mixin 和哪些切入点 pointcut 将被应用到某个或某些类:
aspect 切面名称 for 类名[导入]
[切入点]
end
例如
aspect MyAspect for Customerend
这是为特定某个类(Customer)声明切面的示例。
aspect MyAspect for [ My.Namespace.Classes excludes(Customer,Author) ]end
这是为特定某个命名空间(My.Namespace.Classes)中的类声明切面的示例,但把 Customer, Author 两个类排除在外。
aspect MyAspect for [ assignableFrom(Customer) ]end
这是为继承或实现自 Customer 父类或接口的所有类声明切面的示例。
aspect MyAspect for [ customMatcher(自定义匹配器类名) ]end
这是使用了自定义匹配器声明切面的示例。
当你在一个实例中调用了 AspectEngine.Wrap() 方法,基本上 Aspect# 会尝试找出与这个实例匹配的切面。如果匹配了多个切面,将从这个集合中创建一个新的切面并作为这个切面的定义。(???)
如果你需要在匹配切面时采用更特别的语义,你可以通过 customMatcher 关键字(示例如上)提供你自己的切面匹配器。你的类必须实现 IClassMatcher 接口,并编写逻辑使得当这个实例符合你希望的切面要求时返回真值 true 。
6. 引用 include
你可以在一个切面定义中使用一个或多个 include 引用已经定义了的混入 mixin 。
include("键名")这是声明了全局混入映射后的引用方式。
include 类名 in 程序集这是没有声明全局混入映射,需要从程序集中引入的引用方式。
例如
include DigitalGravity.Mixins.Security in DigitalGravity.XProject
include System.Collections.ArrayList in System
end
7. 切入点 pointcut
切入点的目的是为执行通知而定义的一套有效的表达式,
pointcut [目标][方法签名]advice(类名)
advice("键名")
end
『目标』可能是:method、property、propertyread 或 propertywrite。
如果需要你也可以像这样把它们组合起来:
pointcut method|property(*)endpointcut method|propertyread(*)
endpointcut propertywrite(*)
end
但是使用 property|propertywrite 是毫无意义的,你也会因此得到一个错误。
『方法签名』可以简单如一个 (*) 表示所有,或 (System.IList Create(int,*)) 表示所有返回类型为 System.IList 且至少第一个参数类型是 int 的名为 Create 的方法。请注意,在这里,返回值类型和参数类型必须使用完整的类名称,正如 System.IList 而不能只是 IList 。
正则表达式不被完全支持。实际上,你可以只使用 .* 来匹配一个名字的剩余部分,像 (Str.* Create(int, string)) 将匹配所有带有两个参数(第一个参数是 int 类型,第二个参数是 string 类型)并返回一个名称前缀是 Str (例如 String, Strange, Stripissimo)的类型的名为 Create 的方法。
例如
// 所有名为 Name 的读属性和写属性pointcut property(* Name)
end
// 所有如同 C*****Name 一样的读属性和写属性,譬如 CustomerName
pointcut property(string C.*Name)
end
// 返回类型为 void 、没有参数、名为 Perform 的方法
pointcut method(void Perform)
end
// 第一个参数是 String 类型而我们不关心其他参数的名为 Perform 的方法
pointcut method(void Perform(string, *))
end
8. 通知 advice
通知 advice 是一些与切入点有关的代码片段。Aspect# 只支持方法拦截机的通知。
advice("键名")advice(拦截机类名)
advice(拦截机类名 in 程序集名称)
请注意,我们对拦截机使用延迟载入,并且在每次 Wrap() 中一个拦截机只会有一个实例。换言之,多个代理之间不会共享拦截机。
例如
aspect MyAspect for Customerpointcut method(*)
advice(LogInvocationInterceptor)
end
endaspect MyAspect for Customer
pointcut method(*)
advice(Namespace.MyLogger in MyAssembly)
end
end