在JAVA中实现动态接口代理的方法有不少,但显然在.NET中类似的方法彷佛挺难找的 固然这不是说你没法本身写出这方面的东西 它的确不会是个太难的东西 只是会相对麻烦些java
对于动态接口代理对咱们而言它具有有多大的意义?实际上从我角度上看它的意义并不大 不少时候它或许只会是个嚼头 一个花瓶具象解决不了任何问题 数组
那么思考一下动态接口代理是如何实现,咱们就用JAVA语言中的“InvocationHandler & Proxy”的实现方式为概念去思考一下好了 ide
那么姑且先看看下面的JAVA代码函数
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface IFoo { void say(); } class FooHandler implements InvocationHandler { @Override public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable { if (("say").equals(arg1.getName())) { System.out.println("hello world!"); } return null; } } public abstract class Program { public static void main(String[] args) throws InterruptedException { InvocationHandler handler = new FooHandler(); Class<?> clazz = IFoo.class; IFoo foo = (IFoo) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, handler); foo.say(); } }这是JAVA中很形象的一种动态接口代理的方法、从它的动态代码编写结构上咱们很容易看明白一个东西即“ InvocationHandler ”是具象成员的执行体、它主要针对于友元函数
如上图所示,Object只是一个花瓶的具象它不作任何事它只有一件事把调用的任务“桥接”到“InvocationHandler”再由它处理流程(但此时它却又更高级的权限它能够绝对是否处理此调用,但显然你一样能够在具象内作到 但代码可能会变得不是很好看)工具
那么知道了它的思想咱们要如何去实现动态代理接口的工具类呢,那么有必要弄明白既然既然动态生成的具象它全部的友元函数都须要调用“InvocationHandler”来完成 那么显然你确定须要把“InvocationHandler”的引用传入对象ui
一、构造(Constructor)在这里定义构造时提供一个“InvocationHandler”类型的参数输入 这确定是很重要的地方固然你也能够定义一个公共属性或字段在输入引用但显然不是太好spa
private static void CreateConstructor(TypeBuilder tb, FieldBuilder fb) { Type[] args = new Type[] { typeof(InvocationHandler) }; ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, args); ILGenerator il = ctor.GetILGenerator(); // il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Stfld, fb); il.Emit(OpCodes.Ret); }二、后台字段(Blank field)它主要保存对“ InvocationHandler”的一个地址引用,在接口里面调用一个方法或属性时那么就会去使用这个引用 因此这个字段的重要性是很高 固然既然是后台字段确定是不公开私有的字段
private static FieldBuilder CreateField(TypeBuilder tb) { return tb.DefineField("handler", typeof(InvocationHandler), FIELD_ATTRIBUTES); }三、桥接函数体(Bridge function)这显然是花瓶具象内部最麻烦的一个,它须要把调用的参数一个一个的加入固定数组而后再把一些关键信息压入堆栈在桥接给 “ InvocationHandler ”进行处理、可是有些函数内部是没有返回值的那么你还须要对这种函数进行处理 不然会出现一些故障 有返回值的可是桥接给“InvocationHandler”处理 但若是被代理的函数具有返回值 那么不可避免你须要去进行一次转换 “InvocationHandler”返回的是一个Object类型
一、定义固态数组代理
il.Emit(OpCodes.Nop); il.Emit(OpCodes.Ldc_I4, args.Length); il.Emit(OpCodes.Newarr, typeof(object)); il.Emit(OpCodes.Stloc_0);二、把函数调用参数放入数组
for (int i = 0; i < args.Length; i++) { il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, (1 + i)); il.Emit(OpCodes.Box, args[i].ParameterType); il.Emit(OpCodes.Stelem_Ref); }三、桥接到“ InvocationHandler”中进行处理
il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, fb); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, met.MetadataToken); il.Emit(OpCodes.Ldstr, met.Name); il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Call, typeof(InvocationHandler).GetMethod("InvokeMember", BindingFlags.Instance | BindingFlags.Public));四、对“InvocationHandler”的返回值进行处理
if (met.ReturnType == typeof(void)) { il.Emit(OpCodes.Pop); } else { il.Emit(OpCodes.Unbox_Any, met.ReturnType); il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Ldloc_1); } il.Emit(OpCodes.Ret);
没时间说的太详细了 今天就先这样把 下面是一个例子与JAVA的使用上并无太大的一个区别可是显然我这篇文档并非再告诉你如何去使用 这显然没有意义、有时间的话在完善这篇文章的内容吧code
源代码与示例代码的下载地址:http://pan.baidu.com/s/1qYatYSs对象
namespace STDLOGIC_SERVER.AOP.Proxy { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; public static class Program { public interface IFoo { void Say(); } public class FooInvocationHandler : InvocationHandler { object InvocationHandler.InvokeMember(object obj, int rid, string name, params object[] args) { MethodBase met = typeof(IFoo).Module.ResolveMethod(rid); if (met.Name == "Say") { Console.WriteLine("hello world!"); } return null; } } static void Main() { IFoo foo = InterfaceProxy.New<IFoo>(new FooInvocationHandler()); foo.Say(); Console.ReadKey(false); } } }