C#之动态代理的实现

1.什么是代理模式

菜鸟教程上说,代理模式就是为其他对象提供一种代理以控制对这个对象的访问。
我们来举个例子:

    public class Food
    {
        public virtual string Eat(int p1, int p2)
        {
            return "吃";
        }
    }
    public class FoodProxy : Food
    {
        public override string Eat(int p1, int p2)
        {
            Console.WriteLine("煮熟");
            return base.Eat(p1, p2);
        }
    }
    public class Test
    {
        public void Run()
        {
            //Food f = new Food();
            //f.Eat(1,2);
            Food f = new FoodProxy();
            f.Eat(1, 2);
        }
    }

代码解释:
对Food的所有访问都要通过FoodProxy来完成,FoodProxy可以提供一些额外的代码,比如先煮熟,检查是否洗了手之类的。

2.什么是动态代理

动态代理指的就是编码期间是没有这个FoodProxy的,FoodProxy是在程序运行期间动态创建的。

            Type tf = ProxyBuilder<Interceptor>.BuildProxy(typeof(Food));
            Food f = (Food)Activator.CreateInstance(tf);            

这样做的好处是
1.减少了编码期间的耦合,程序员感受不到FoodProxy这个类的存在,一定程度上简化了业务逻辑;
2.对于新的类型Meat,Vegetables不用手动创建新的MeatProxy,VegetablesProxy,一定程度上减少了重复编码;

3.如何实现动态代理 part1

首先,我们引入调用器(Invocation)和拦截器(Interceptor)的感念。

    public class Invocation
    {
        public object[] Parameter { get; set; }
        public Delegate DelegateMethod { get; set; }
        public object Proceed()
        {
            return this.DelegateMethod.DynamicInvoke(Parameter);
        }
    }
    public class Interceptor
    {
        public object Intercept(Invocation invocation)
        {
            Console.WriteLine("煮熟");
            return invocation.Proceed();
        }
    }
    public class ProxyBuilder
    {
        public static Type BuildProxy(Type targetType)
        {
            Type result = null;
            if (targetType == typeof(Food))
            {
                result = typeof(FoodProxyExample);
            }
            else if (targetType == typeof(Meat))
            {
                result = typeof(MeatProxyExample);
            }
            return result;
        }
    }
    public class Food
    {
        public virtual string Eat(int p1, int p2)
        {
            return "吃";
        }
    }
    public class FoodProxyExample : Food
    {
        public override string Eat(int p1, int p2)
        {
            object[] Parameter = new object[2];
            Parameter[0] = p1;
            Parameter[1] = p2;
            Func<int, int, string> DelegateMethod = base.Eat;
            Invocation invocation = new Invocation();
            invocation.Parameter = Parameter;
            invocation.DelegateMethod = DelegateMethod;

            Interceptor interceptor = new Interceptor();
            return (string)interceptor.Intercept(invocation);
        }
    }
    public class Meat
    {
        public virtual string Eat(int p1)
        {
            return "吃";
        }
    }
    public class MeatProxyExample : Meat
    {
        public override string Eat(int p1)
        {
            object[] Parameter = new object[1];
            Parameter[0] = p1;
            Func<int, string> DelegateMethod = base.Eat;
            Invocation invocation = new Invocation();
            invocation.Parameter = Parameter;
            invocation.DelegateMethod = DelegateMethod;

            Interceptor interceptor = new Interceptor();
            return (string)interceptor.Intercept(invocation);
        }
    }

代码解释:
可以看到,调用器(Invocation)和拦截器(Interceptor)的作用就是把Console.WriteLine(“吃”)这部分业务逻辑代码从框架代码中独立出来。

但显然,上述 ProxyBuilder.BuildProxy(typeof(Food)) 中并没有真正意义上动态创建Food的代理,如果换成 ProxyBuilder.BuildProxy(typeof(Vegetables)) ,则又需要硬编码一个VegetablesProxyExample。
那么能否根据一个未知的类型XXX去动态的生成一个XXXProxyExample呢?

4.如何实现动态代理 part2

接下去将采用System.Reflection.Emit来动态生成一个类。
大家知道,编译器会把源代码(C#)编译成托管代码(IL),托管代码在公共语言运行库(CLR)中运行。当方法被调用时,再通过即时编译器(JIT)编译成机器码。而Emit的作用可以理解为直接操作托管代码来生成类或者方法。
框架代码如下:

    /// <summary>
    /// 代理生成类
    /// </summary>
    public class ProxyBuilder<T> where T : IInterceptor, new()
    {
        protected static AssemblyName DemoName = new AssemblyName("DynamicAssembly");
        /// <summary>
        /// 在内存中保存好存放代理类的动态程序集
        / </summary>
        protected static AssemblyBuilder assyBuilder = AssemblyBuilder.DefineDynamicAssembly(DemoName, AssemblyBuilderAccess.Run);
        /// <summary>
        /// 在内存中保存好存放代理类的托管模块
        /// </summary>
        protected static ModuleBuilder modBuilder = assyBuilder.DefineDynamicModule(DemoName.Name);
        /// <summary>
        /// 动态构造targetType的代理类
        /// </summary>
        /// <returns></returns>
        public static Type BuildProxy(Type targetType, bool declaredOnly = false)
        {
            //创建一个类型 
            if (targetType.IsInterface)
            {
                throw new Exception("cannot create a proxy class for the interface");
            }
            Type TypeOfParent = targetType;
            Type[] TypeOfInterfaces = new Type[0];
            TypeBuilder typeBuilder = modBuilder.DefineType(targetType.Name + "Proxy" + Guid.NewGuid().ToString("N"), TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit, TypeOfParent, TypeOfInterfaces);
            BindingFlags bindingFlags;
            if (declaredOnly)
            {
                bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            }
            else
            {
                bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
            }
            MethodInfo[] targetMethods = targetType.GetMethods(bindingFlags);
            //遍历各个方法
            foreach (MethodInfo targetMethod in targetMethods)
            {
                //只挑出virtual的实例方法进行重写
                //只挑出打了RewriteAttribute标记的方法进行重写
                if (targetMethod.IsVirtual && !targetMethod.IsStatic && !targetMethod.IsFinal && !targetMethod.IsAssembly && targetMethod.GetCustomAttributes(true).Any(e => (e as RewriteAttribute != null)))
                {
                    Type[] paramType;
                    Type returnType;
                    ParameterInfo[] paramInfo;
                    Type delegateType = GetDelegateType(targetMethod, out paramType, out returnType, out paramInfo);
                    Type interceptorType = typeof(T);
                    MethodBuilder methodBuilder = typeBuilder.DefineMethod(targetMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig, returnType, paramType);
                    for (var i = 0; i < paramInfo.Length; i++)
                    {
                        ParameterBuilder paramBuilder = methodBuilder.DefineParameter(i + 1, paramInfo[i].Attributes, paramInfo[i].Name);
                        if (paramInfo[i].HasDefaultValue)
                        {
                            paramBuilder.SetConstant(paramInfo[i].DefaultValue);
                        }
                    }
                    ILGenerator il = methodBuilder.GetILGenerator();
                    //下面的il相当于
                    //public class parent
                    //{
                    //    public virtual string test(List<string> p1, int p2)
                    //    {
                    //        return "123";
                    //    }
                    //}
                    //public class child : parent
                    //{
                    //    public override string test(List<string> p1, int p2)
                    //    {
                    //        object[] Parameter = new object[2];
                    //        Parameter[0] = p1;
                    //        Parameter[1] = p2;
                    //        Func<List<string>, int, string> DelegateMethod = base.test;

                    //        Invocation invocation = new Invocation();
                    //        invocation.Parameter = Parameter;
                    //        invocation.DelegateMethod = DelegateMethod;
                    //        Interceptor interceptor = new Interceptor();
                    //        return (string)interceptor.Intercept(invocation);
                    //    }
                    //}

                    Label label1 = il.DefineLabel();

                    il.DeclareLocal(typeof(object[]));
                    il.DeclareLocal(delegateType);
                    il.DeclareLocal(typeof(Invocation));
                    il.DeclareLocal(interceptorType);
                    LocalBuilder re = null;
                    if (returnType != typeof(void))
                    {
                        re = il.DeclareLocal(returnType);
                    }
                    il.Emit(OpCodes.Ldc_I4, paramType.Length);
                    il.Emit(OpCodes.Newarr, typeof(object));
                    il.Emit(OpCodes.Stloc, 0);
                    for (var i = 0; i < paramType.Length; i++)
                    {
                        il.Emit(OpCodes.Ldloc, 0);
                        il.Emit(OpCodes.Ldc_I4, i);
                        il.Emit(OpCodes.Ldarg, i + 1);
                        if (paramType[i].IsValueType)
                        {
                            il.Emit(OpCodes.Box, paramType[i]);
                        }
                        il.Emit(OpCodes.Stelem_Ref);
                    }
                    il.Emit(OpCodes.Ldarg, 0);
                    il.Emit(OpCodes.Ldftn, targetMethod);
                    il.Emit(OpCodes.Newobj, delegateType.GetConstructors()[0]);
                    il.Emit(OpCodes.Stloc, 1);
                    il.Emit(OpCodes.Newobj, typeof(Invocation).GetConstructors(BindingFlags.Public | BindingFlags.Instance).First(e => e.GetParameters().Length == 0));
                    il.Emit(OpCodes.Stloc, 2);
                    il.Emit(OpCodes.Ldloc, 2);
                    il.Emit(OpCodes.Ldloc, 0);
                    il.Emit(OpCodes.Callvirt, typeof(Invocation).GetMethod("set_Parameter"));
                    il.Emit(OpCodes.Ldloc, 2);
                    il.Emit(OpCodes.Ldloc, 1);
                    il.Emit(OpCodes.Callvirt, typeof(Invocation).GetMethod("set_DelegateMethod"));
                    il.Emit(OpCodes.Newobj, interceptorType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).First(e => e.GetParameters().Length == 0));
                    il.Emit(OpCodes.Stloc, 3);
                    il.Emit(OpCodes.Ldloc, 3);
                    il.Emit(OpCodes.Ldloc, 2);
                    il.Emit(OpCodes.Callvirt, interceptorType.GetMethod("Intercept"));
                    if (returnType != typeof(void))
                    {
                        il.Emit(OpCodes.Castclass, returnType);
                        il.Emit(OpCodes.Stloc_S, re);
                        il.Emit(OpCodes.Br_S, label1);
                        il.MarkLabel(label1);
                        il.Emit(OpCodes.Ldloc_S, re);
                    }
                    else
                    {
                        il.Emit(OpCodes.Pop);
                    }
                    il.Emit(OpCodes.Ret);
                }
            }
            //真正创建,并返回
            Type proxyType = typeBuilder.CreateType();
            return proxyType;
        }
        /// <summary>
        /// 通过MethodInfo获得其参数类型列表,返回类型,和委托类型
        /// </summary>
        /// <param name="targetMethod"></param>
        /// <param name="paramType"></param>
        /// <param name="returnType"></param>
        /// <returns></returns>
        public static Type GetDelegateType(MethodInfo targetMethod, out Type[] paramType, out Type returnType, out ParameterInfo[] paramInfo)
        {
            paramInfo = targetMethod.GetParameters();
            //paramType
            paramType = new Type[paramInfo.Length];
            for (int i = 0; i < paramInfo.Length; i++)
            {
                paramType[i] = paramInfo[i].ParameterType;
            }
            //returnType
            returnType = targetMethod.ReturnType;
            //delegateType
            Type delegateType;
            if (returnType == typeof(void))
            {
                switch (paramType.Length)
                {
                    case 0:
                        delegateType = typeof(Action);
                        break;
                    case 1:
                        delegateType = typeof(Action<>).MakeGenericType(paramType);
                        break;
                    case 2:
                        delegateType = typeof(Action<,>).MakeGenericType(paramType);
                        break;
                    case 3:
                        delegateType = typeof(Action<,,>).MakeGenericType(paramType);
                        break;
                    case 4:
                        delegateType = typeof(Action<,,,>).MakeGenericType(paramType);
                        break;
                    case 5:
                        delegateType = typeof(Action<,,,,>).MakeGenericType(paramType);
                        break;
                    case 6:
                        delegateType = typeof(Action<,,,,,>).MakeGenericType(paramType);
                        break;
                    case 7:
                        delegateType = typeof(Action<,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 8:
                        delegateType = typeof(Action<,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 9:
                        delegateType = typeof(Action<,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 10:
                        delegateType = typeof(Action<,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 11:
                        delegateType = typeof(Action<,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 12:
                        delegateType = typeof(Action<,,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 13:
                        delegateType = typeof(Action<,,,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 14:
                        delegateType = typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    case 15:
                        delegateType = typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                    default:
                        delegateType = typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(paramType);
                        break;
                }
            }
            else
            {
                Type[] arr = new Type[paramType.Length + 1];
                for (int i = 0; i < paramType.Length; i++)
                {
                    arr[i] = paramType[i];
                }
                arr[paramType.Length] = returnType;
                switch (paramType.Length)
                {
                    case 0:
                        delegateType = typeof(Func<>).MakeGenericType(arr);
                        break;
                    case 1:
                        delegateType = typeof(Func<,>).MakeGenericType(arr);
                        break;
                    case 2:
                        delegateType = typeof(Func<,,>).MakeGenericType(arr);
                        break;
                    case 3:
                        delegateType = typeof(Func<,,,>).MakeGenericType(arr);
                        break;
                    case 4:
                        delegateType = typeof(Func<,,,,>).MakeGenericType(arr);
                        break;
                    case 5:
                        delegateType = typeof(Func<,,,,,>).MakeGenericType(arr);
                        break;
                    case 6:
                        delegateType = typeof(Func<,,,,,,>).MakeGenericType(arr);
                        break;
                    case 7:
                        delegateType = typeof(Func<,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 8:
                        delegateType = typeof(Func<,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 9:
                        delegateType = typeof(Func<,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 10:
                        delegateType = typeof(Func<,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 11:
                        delegateType = typeof(Func<,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 12:
                        delegateType = typeof(Func<,,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 13:
                        delegateType = typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 14:
                        delegateType = typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    case 15:
                        delegateType = typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                    default:
                        delegateType = typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(arr);
                        break;
                }
            }
            return delegateType;

        }
    }
    /// <summary>
    /// 拦截器
    /// </summary>
    public interface IInterceptor
    {
        object Intercept(Invocation invocation);
    }
    /// <summary>
    /// 调用器
    /// </summary>
    public class Invocation
    {
        public object[] Parameter { get; set; }
        public Delegate DelegateMethod { get; set; }
        public object Proceed()
        {
            return this.DelegateMethod.DynamicInvoke(Parameter);
        }
    }
    /// <summary>
    /// 为要拦截的方法打上标记
    /// </summary>
    public class RewriteAttribute : System.Attribute
    {
    }

业务代码如下:

	/// <summary>
    /// 具体的某个拦截器
    /// </summary>
    public class Interceptor : IInterceptor
    {
        public object Intercept(Invocation invocation)
        {
            Console.WriteLine("煮熟");
            return invocation.Proceed();
        }
    }
    public class Food
    {
        [Rewrite]
        public virtual string Eat(int p1, int p2)
        {
            return "吃";
        }
    }
    public class Test
    {
        public void Run()
        {
            Food f = (Food)Activator.CreateInstance(ProxyBuilder<Interceptor>.BuildProxy(typeof(Food)));
        }
    }

代码解释:
RewriteAttribute的作用是标记被代理类中的virtual方法,让框架只重写被标记的方法,这样做的目的有
1.提高生成代理类的速度;
2.某个类中哪些方法被代理执行,哪些方法没有被代理执行有迹可循;
拦截器改用interface,把业务实现作为泛型传入ProxyBuilder,这样做的目的是把拦截业务独立于动态代理框架之外。

5.如何实现动态代理 part3

上面的代码已经基本实现功能,但是每次调用BuildProxy都会有不小的性能消耗。
这里使用一个单例字典来解决问题。思路就是每次通过Food生成FoodProxy时,优先去字典中查找Food的代理类,如果找到了就直接使用,如果找不到则通过BuildProxy生成且在生成后放入字典。
框架代码如下(在part2的基础上新增):

    /// <summary>
    /// Type和Type的代理类的封装
    /// </summary>
    public class ProxyType<T> where T : IInterceptor, new()
    {
        #region 属性
        public Type Type { get; set; }
        public Type Proxy { get; set; }
        #endregion
        #region 构造函数
        public ProxyType(Type type)
        {
            this.Type = type;
            this.Proxy = ProxyBuilder<T>.BuildProxy(type);
        }
        #endregion
    }
	public class ProxyTypeCollection<T> : IEnumerable<ProxyType<T>> where T : IInterceptor, new()
    {
        #region 单例模式
        private static volatile ProxyTypeCollection<T> _instance = null;
        private static readonly object lockHelper = new object();
        public static ProxyTypeCollection<T> Instance()
        {
            if (_instance == null)
            {
                lock (lockHelper)
                {
                    if (_instance == null)
                        _instance = new ProxyTypeCollection<T>();
                }
            }
            return _instance;
        }
        #endregion
        #region 属性
        private readonly Dictionary<Type, ProxyType<T>> _Items;
        #endregion
        #region 构造函数
        private ProxyTypeCollection()
        {
            _Items = new Dictionary<Type, ProxyType<T>>();
        }
        #endregion
        #region Collection
        public ProxyType<T> this[Type name]
        {
            get
            {
                ProxyType<T> value;
                if (!_Items.TryGetValue(name, out value))
                {
                    value = new ProxyType<T>(name);
                    this.Add(value);
                }
                return value;
            }
        }
        internal void Add(ProxyType<T> value)
        {
            var name = value.Type;
            ProxyType<T> p;
            if (!_Items.TryGetValue(name, out p))
            {
                lock (lockHelper)
                {
                    if (!_Items.TryGetValue(name, out p))
                    {
                        _Items.Add(name, value);
                    }
                }
            }
        }
        public bool ContainsKey(Type name)
        {
            return _Items.ContainsKey(name);
        }
        public ICollection<Type> Names
        {
            get { return _Items.Keys; }
        }
        public int Count
        {
            get { return _Items.Count; }
        }
        #endregion
        #region 迭代器
        public IEnumerator<ProxyType<T>> GetEnumerator()
        {
            foreach (var item in _Items)
            {
                yield return item.Value;
            }
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _Items.Values.GetEnumerator();
        }
        #endregion
    }
    /// <summary>
    /// 动态代理的工厂
    /// 说明:
    /// 在第一次需要用到代理时动态生成代理类,之后的使用均调用已经生成的代理类
    /// 规则:
    /// 1.不能为接口创建代理类代理类
    /// 2.父级必须有空的构造函数
    /// 3.只重写virtual的实例方法
    /// 使用说明:
    /// 1.通过CreateInstance生成代理类
    /// 2.通过自定义IInterceptor的实现来自定义代理类对virtual实例方法的重写
    /// </summary>
    public class ProxyFactory<T> where T:IInterceptor,new()
    {
        public S CreateInstance<S>() where S : class
        {
            return (S)Activator.CreateInstance(ProxyTypeCollection<T>.Instance()[typeof(S)].Proxy);
        }

        public object CreateInstance(Type type)
        {
            return Activator.CreateInstance(ProxyTypeCollection<T>.Instance()[type].Proxy);
        }
    }

业务代码

	/// <summary>
    /// 具体的某个拦截器
    /// </summary>
    public class Interceptor : IInterceptor
    {
        public object Intercept(Invocation invocation)
        {
            Console.WriteLine("煮熟");
            return invocation.Proceed();
        }
    }
    public class Food
    {
        [Rewrite]
        public virtual string Eat(int p1, int p2)
        {
            return "吃";
        }
    }
    public class Test
    {
        public void Run()
        {
            Food f = new ProxyFactory<Interceptor>().CreateInstance<Food>();
        }
    }

如此一来,编程者不用感知到FoodProxy的存在,而实际生效的却是FoodProxy。

6.总结

动态代理由于需要工厂ProxyFactory去创建代理类的实例化对象,往往需要配合其他框架使用,比如AOP。
有兴趣的可以看一下这篇文章《C#之AOP的实现》

以上就是动态代理的全部内容,如有纰漏和建议,欢迎大家留言指出。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值