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的实现》
以上就是动态代理的全部内容,如有纰漏和建议,欢迎大家留言指出。