目的:
可以將castle.dynamicProxy當成代碼生成器,快速的生成自己想的代碼.這個庫經歷了這么多年的測試,應該可以用了:D
概念:
IInterceptor:攔截器
當方法(屬性的本質是兩個方法的組合)被調用時,則執行這個攔截器的代碼.
但是,默認情況下,一個方法的調用被生成了一個攔截器.如果用于DC代碼生成,這似乎有點浪費資源.
public class SimpleLogInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine(">>" + invocation.Method.Name); invocation.Proceed(); } }
測試:
ProxyGenerator generator = new ProxyGenerator();
SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>( new SimpleLogInterceptor(), new CallingLogInterceptor()); //這里可以指定多個攔截器 entity.Name = "Richie"; entity.Age = 50; Console.WriteLine("The entity is: " + entity); Console.WriteLine("Type of the entity: " + entity.GetType().FullName); Console.ReadKey();
IInterceptorSelector 與 IProxyGenerationHook
實際中并不一定所有方法都需要運用全部的攔截器,對方法調用有選擇性的選擇攔截器有2種方式,例如:
public class InterceptorSelector : IInterceptorSelector { public IInterceptor[] SelectInterceptors(Type type, MethodInfo method, IInterceptor[] interceptors) { if (method.Name.StartsWith("set_")) return interceptors; //這里可以決定什么的方法返回什么樣的攔截器 else return interceptors.Where(i => i is CallingLogInterceptor).ToArray<IInterceptor>(); } }
public class InterceptorFilter : IProxyGenerationHook { public bool ShouldInterceptMethod(Type type, MethodInfo memberInfo) { return memberInfo.IsSpecialName && (memberInfo.Name.StartsWith("set_") || memberInfo.Name.StartsWith("get_")); //什么樣的方法可以被攔截? } public void NonVirtualMemberNotification(Type type, MemberInfo memberInfo) {
//類型為非虛方法時,這里可以得到提示,將被調用 } public void MethodsInspected() { } }
測試代碼:
ProxyGenerator generator = new ProxyGenerator(); var options = new ProxyGenerationOptions(new InterceptorFilter()) { Selector = new InterceptorSelector() }; SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>( options, new SimpleLogInterceptor(), new CallingLogInterceptor()); entity.Name = "Richie"; entity.Age = 50; Console.WriteLine("The entity is: " + entity); Console.WriteLine("Type of the entity: " + entity.GetType().FullName); Console.ReadKey();
IProxyGenerationHook接口決定整個方法是否運用攔截器,他是在動態構造代理類型的時候使用的;而IInterceptorSelector接口決定某個方法該運用哪些攔截器,他在每次調用被攔截的方法時執行
上面的示例只對setter和getter方法進行攔截,并且對getter方法只使用CallingLogInterceptor這個攔截器
導出、生成代理類型
Castle Dynamic Proxy允許我們將運行時生成的代理類型生成dll文件存到磁盤上,下次啟動時通過加載這個dll文件可以避免動態生成代理類型
var scope = new ModuleScope( true, ModuleScope.DEFAULT_ASSEMBLY_NAME, ModuleScope.DEFAULT_FILE_NAME, "DynamicProxyTest.Proxies", "DynamicProxyTest.Proxies.dll"); var builder = new DefaultProxyBuilder(scope); var generator = new ProxyGenerator(builder); var options = new ProxyGenerationOptions(new InterceptorFilter()) { Selector = new InterceptorSelector() }; SimpleSamepleEntity entity = generator.CreateClassProxy<SimpleSamepleEntity>( options, new SimpleLogInterceptor(), new CallingLogInterceptor()); IStorageNode node = generator.CreateInterfaceProxyWithTargetInterface<IStorageNode>( new StorageNode("master") , new DualNodeInterceptor(new StorageNode("slave")) , new CallingLogInterceptor()); options = new ProxyGenerationOptions(); options.AddMixinInstance(new ClassA()); ClassB objB = generator.CreateClassProxy<ClassB>(options, new CallingLogInterceptor()); scope.SaveAssembly(false);
注意:上面用到的攔截器和其他測試類都必須加上[Serializable]屬性
可以用reflector查看生成的dll,大致了解代理對象是如何工作的
啟動時,可以使用
scope.LoadAssemblyIntoCache(assembly);
將生成的代理類型加載到內存中,其中assembly需要我們手動加載
參考原文:
http://www.cnblogs.com/RicCC/archive/2010/03/15/castle-dynamic-proxy.html
文章列表