假设我们定义一个ExceptionHandlingInterceptor来实施自动化异常处理,当我们在创建这个Interceptor的时候需要提供注册的异常处理类型的名称,那么我们需要采用如下的形式来定义对应的这个IntercecptorAttribute。如下面的代码片段所示,我们在调用Use<ExceptionHandlingInterceptor>方法的时候就需要显式指定这个策略名称。
1: [AttributeUsage(AttributeTargets.Method|AttributeTargets.)] 2: public class HandleExceptionAttribute : InterceptorAttribute 3: { 4: public string ExceptionPolicy {get;} 5: public string HandleExceptionAttribute(string exceptionPolicy) 6: { 7: this.ExceptionPolicy = exceptionPolicy; 8: } 9: public override void Use(IInterceptorChainBuilder builder) 10: { 11: builder.Use<ExceptionHandlingInterceptor>(this.Order,this.ExceptionPolicy); 12: } 13: }
有的时候,IntercecptorAttribute在注册对应Interceptor的时候需要使用到应用到当前方法或者类型上的其他Attribute。举个简单的例子,上述的这个HandleExceptionAttribute实际上是自动提供异常处理策略名称,假设异常处理系统自身使用另外一个独立的ExceptionPolicyAttribute采用如下的形式来提供这个策略。
1: public class Foobar 2: { 3: [ExceptionPolicy("DefaultPolicy") 4: public void Invoke() 5: { 6: ... 7: } 8: }
这个问题很好解决,因为InterceptorAttribute自身提供了应用到目标方法或者类型上的所有Attribute,所以上述这个HandleExceptionAttribute可以采用如下的定义方式。
1: [AttributeUsage(AttributeTargets.Method)] 2: public class HandleExceptionAttribute : InterceptorAttribute 3: { 4: public override void Use(IInterceptorChainBuilder builder) 5: { 6: ExceptionPolicyAttribute attribute = this.Attributes.ofType<ExceptionPolicyAttribute>().First(); 7: builder.Use<Exception>(this.Order, attribute.ExceptionPolicy); 8: } 9: }
六、应用InterceptorAttributeInterceptor通过对应的InterceptorAttribute被应用到某个方法或者类型上,我们在应用InterceptorAttribute可以利用其Order属性确定Interceptor的排列(执行)顺序。如下面的代码片段所示, HandleExceptionAttribute和CacheReturnValueAttribute分别被应用到Foobar类型和Invoke方法上,我要求ExceptionHandlingInterceptor能够处理CacheInterceptor抛出的异常, 那么前者必须由于后者执行,所以我通过Order属性控制了它们的执行顺序。值得一提的是,目前我们支持两个拦截机制,一种是基于接口,另一种是基于虚方法。如果采用基于接口的拦截机制,我要求InterceptorAttribute应用在实现类型或者其方法上,应用在接口和其方法上的InterceptorAttribute将无效。
1: [HandleException("defaultPolicy", Order = 1)] 2: public class Foobar: IFoobar 3: { 4: [CacheReturnValue(this.Order = 2)] 5: public Data LoadData() 6: { 7: ... 8: } 9: }
如果我们在类型上应用了某个InterceptorAttribute,但是对应的Interceptor却并不希望应用到某个方法中,我们可以利用NonInterceptableAttribute采用如下的形式将它们屏蔽,
1: [CacheReturnValue] 2: public class Foobar 3: { 4: ... 5: [NonInterceptable(typeof(CacheReturnValueAttribute)] 6: public Data GetRealTypeData() 7: {...} 8: }
七、以Dependency Injection的形式提供Proxy