对于VirtualMethodInterceptor,还有需要澄清的地方:
1、代理是如何实现IInterceptingProxy接口的:
(1)先从以下实验代码了解 动态创建类 和创建的类如何实现接口:
public interface IHello
{
void SayHello();
}
private void button3_Click(object sender, EventArgs e)
{
AppDomain domain = AppDomain.CurrentDomain;
//动态程序集
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
//动态程序集模块
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("helloWorldTypeBuilder");
//运行时创建类
TypeBuilder helloWorldTypeBuilder = moduleBuilder.DefineType("hello");
//声明实现IHello接口
helloWorldTypeBuilder.AddInterfaceImplementation(typeof(IHello));
//定义SayHello方法
MethodBuilder myMethodBuilder =
helloWorldTypeBuilder.DefineMethod("SayHello2",
MethodAttributes.Public | MethodAttributes.Virtual,
null,
null);
// 方法体开始
ILGenerator myMethodIL = myMethodBuilder.GetILGenerator();
myMethodIL.Emit(OpCodes.Ldstr, "hello world");
Type[] showParameters = { typeof(String) };
MethodInfo messageBoxShow = typeof(MessageBox).GetMethod("Show", showParameters);
myMethodIL.Emit(OpCodes.Call, messageBoxShow);
myMethodIL.Emit(OpCodes.Pop);
myMethodIL.Emit(OpCodes.Ret);
// 方法体结束
//方法体注入接口SayHello方法
MethodInfo sayHelloMethod = typeof(IHello).GetMethod("SayHello");
helloWorldTypeBuilder.DefineMethodOverride(myMethodBuilder, sayHelloMethod);
//调用
Type test = helloWorldTypeBuilder.CreateType();//创建动态类
var instance = Activator.CreateInstance(test);
((IHello)instance).SayHello();
test.GetMethod("SayHello2").Invoke(instance, null);
}
上面的理解了,分析源码就清楚多了。
(2)分析源码,了解IInterceptingProxy是如何被实现的:
在E:\Program Files\Microsoft Unity Application Block 2.0\UnitySource\Source\Unity.Interception\Src\Intercept.cs
public static object NewInstanceWithAdditionalInterfaces(
Type type,
ITypeInterceptor interceptor,
IEnumerable<IInterceptionBehavior> interceptionBehaviors,
IEnumerable<Type> additionalInterfaces,
params object[] constructorParameters)
{
Guard.ArgumentNotNull(type, "type");
Guard.ArgumentNotNull(interceptor, "interceptor");
Guard.ArgumentNotNull(interceptionBehaviors, "interceptionBehaviors");
Guard.ArgumentNotNull(additionalInterfaces, "additionalInterfaces");
if (!interceptor.CanIntercept(type))
{
throw new ArgumentException(
string.Format(
CultureInfo.CurrentCulture,
Resources.InterceptionNotSupported,
type.FullName),
"type");
}
var behaviors = interceptionBehaviors.ToList();
if(behaviors.Where(ib => ib == null).Count() > 0)
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, Resources.NullBehavior),
"interceptionBehaviors");
}
Type implementationType = type;
var activeBehaviors = behaviors.Where(ib => ib.WillExecute);
Type[] allAdditionalInterfaces = GetAllAdditionalInterfaces(activeBehaviors, additionalInterfaces);
Type interceptionType = interceptor.CreateProxyType(implementationType, allAdditionalInterfaces);
var proxy = (IInterceptingProxy)Activator.CreateInstance(interceptionType, constructorParameters);
foreach (IInterceptionBehavior interceptionBehavior in activeBehaviors)
{
proxy.AddInterceptionBehavior(interceptionBehavior);
}
return proxy;
}
CreateProxyType在 E:\Program Files\Microsoft Unity Application Block 2.0\UnitySource\Source\Unity.Interception\Src\Interceptors\TypeInterceptors\VirtualMethodInterception\VirtualMethodInterceptor.cs
public Type CreateProxyType(Type t, params Type[] additionalInterfaces)
{
Guard.ArgumentNotNull(t, "t");
Guard.ArgumentNotNull(additionalInterfaces, "additionalInterfaces");
if (!CanIntercept(t))
{
throw new InvalidOperationException(
string.Format(CultureInfo.CurrentCulture, Resources.InterceptionNotSupported, t.Name));
}
Type interceptorType;
Type typeToDerive = t;
bool genericType = false;
if (t.IsGenericType)
{
typeToDerive = t.GetGenericTypeDefinition();
genericType = true;
}
GeneratedTypeKey key = new GeneratedTypeKey(typeToDerive, additionalInterfaces);
lock (derivedClasses)
{
if (!derivedClasses.TryGetValue(key, out interceptorType))
{
InterceptingClassGenerator generator =
new InterceptingClassGenerator(typeToDerive, additionalInterfaces);
interceptorType = generator.GenerateType();
derivedClasses[key] = interceptorType;
}
}
if (genericType)
{
interceptorType = interceptorType.MakeGenericType(t.GetGenericArguments());
}
return interceptorType;
}
类InterceptingClassGenerator 在 E:\Program Files\Microsoft Unity Application Block 2.0\UnitySource\Source\Unity.Interception\Src\Interceptors\TypeInterceptors\VirtualMethodInterception\InterceptingClassGeneration\InterceptingClassGenerator.cs
构造函数:
{
this.typeToIntercept = typeToIntercept;
this.additionalInterfaces = additionalInterfaces;
CreateTypeBuilder();
}
CreateTypeBuilder:
private void CreateTypeBuilder()
{
TypeAttributes newAttributes = typeToIntercept.Attributes;
newAttributes = FilterTypeAttributes(newAttributes);
Type baseClass = GetGenericType(typeToIntercept);
ModuleBuilder moduleBuilder = GetModuleBuilder();
typeBuilder = moduleBuilder.DefineType(
"DynamicModule.ns.Wrapped_" + typeToIntercept.Name + "_" + Guid.NewGuid().ToString("N"),
newAttributes,
baseClass);//由此看见继承于typeToIntercept
DefineGenericArguments(typeBuilder, baseClass);
// 实现接口靠下面这句
proxyInterceptionPipelineField = InterceptingProxyImplementor.ImplementIInterceptingProxy(typeBuilder);
}
ImplementIInterceptingProxy 在 E:\Program Files\Microsoft Unity Application Block 2.0\UnitySource\Source\Unity.Interception\Src\Interceptors\TypeInterceptors\VirtualMethodInterception\InterceptingClassGeneration\InterceptingProxyImplementor.cs
internal static FieldBuilder ImplementIInterceptingProxy(TypeBuilder typeBuilder)
{
typeBuilder.AddInterfaceImplementation(typeof(IInterceptingProxy));//声明实现IInterceptingProxy接口
FieldBuilder proxyInterceptorPipelineField =
typeBuilder.DefineField(
"pipeline",
typeof(InterceptionBehaviorPipeline),
FieldAttributes.Private | FieldAttributes.InitOnly);
// 方法体注入靠下面这句
ImplementAddInterceptionBehavior(typeBuilder, proxyInterceptorPipelineField);
return proxyInterceptorPipelineField;
}
private static void ImplementAddInterceptionBehavior(TypeBuilder typeBuilder, FieldInfo proxyInterceptorPipelineField)
{
// Declaring method builder
// Method attributes
const MethodAttributes methodAttributes = MethodAttributes.Private | MethodAttributes.Virtual
| MethodAttributes.Final | MethodAttributes.HideBySig
| MethodAttributes.NewSlot;
MethodBuilder methodBuilder =
typeBuilder.DefineMethod(
"Microsoft.Practices.Unity.InterceptionExtension.IInterceptingProxy.AddInterceptionBehavior",
methodAttributes);
// Setting return type
methodBuilder.SetReturnType(typeof(void));
// Adding parameters
methodBuilder.SetParameters(typeof(IInterceptionBehavior));
// Parameter method
methodBuilder.DefineParameter(1, ParameterAttributes.None, "interceptor");
ILGenerator il = methodBuilder.GetILGenerator();
// Writing body
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, proxyInterceptorPipelineField);
il.Emit(OpCodes.Ldarg_1);
il.EmitCall(OpCodes.Callvirt, InterceptionBehaviorPipelineMethods.Add, null);//IInterceptingProxy.AddInterceptionBehavior实际调的是红色
il.Emit(OpCodes.Ret);
typeBuilder.DefineMethodOverride(methodBuilder,IInterceptingProxyMethods.AddInterceptionBehavior);//红色的是AddInterceptionBehavior的methodinfo
}
InterceptionBehaviorPipelineMethods 在 Unity\Unity\Unity.Interception\Src\Interceptors\TypeInterceptors\VirtualMethodInterception\InterceptingClassGeneration\InterceptionBehaviorPipelineMethods.cs
internal static class InterceptionBehaviorPipelineMethods
{
internal static ConstructorInfo Constructor
{
get { return StaticReflection.GetConstructorInfo(() => new InterceptionBehaviorPipeline()); }
}
internal static MethodInfo Add
{
get { return StaticReflection.GetMethodInfo((InterceptionBehaviorPipelinepip) => pip.Add(null)); }
}
internal static MethodInfo Invoke
{
get { return StaticReflection.GetMethodInfo((InterceptionBehaviorPipeline pip) => pip.Invoke(null, null)); }
}
}
InterceptionBehaviorPipeline 在 E:\Program Files\Microsoft Unity Application Block 2.0\UnitySource\Source\Unity.Interception\Src\InterceptionBehaviors\InterceptionBehaviorPipeline.cs
public class InterceptionBehaviorPipeline
{
private readonly List<IInterceptionBehavior> interceptionBehaviors;
/// <summary>
/// Creates a new <see cref="HandlerPipeline"/> with an empty pipeline.
/// </summary>
public InterceptionBehaviorPipeline()
{
interceptionBehaviors = new List<IInterceptionBehavior>();
}
/// <summary>
/// Creates a new <see cref="HandlerPipeline"/> with the given collection
/// of <see cref="ICallHandler"/>s.
/// </summary>
/// <param name="interceptionBehaviors">Collection of interception behaviors to add to the pipeline.</param>
public InterceptionBehaviorPipeline(IEnumerable<IInterceptionBehavior> interceptionBehaviors)
{
Guard.ArgumentNotNull(interceptionBehaviors, "interceptionBehaviors");
this.interceptionBehaviors = new List<IInterceptionBehavior>(interceptionBehaviors);
}
/// <summary>
/// Get the number of interceptors in this pipeline.
/// </summary>
public int Count
{
get { return interceptionBehaviors.Count; }
}
/// <summary>
/// Execute the pipeline with the given input.
/// </summary>
/// <param name="input">Input to the method call.</param>
/// <param name="target">The ultimate target of the call.</param>
/// <returns>Return value from the pipeline.</returns>
public IMethodReturn Invoke(IMethodInvocation input, InvokeInterceptionBehaviorDelegate target)
{
if (interceptionBehaviors.Count == 0)
{
return target(input, null);
}
int interceptorIndex = 0;
IMethodReturn result = interceptionBehaviors[0].Invoke(input, delegate
{
++interceptorIndex;
if (interceptorIndex < interceptionBehaviors.Count)
{
return interceptionBehaviors[interceptorIndex].Invoke;
}
else
{
return target;
}
});
return result;
}
/// <summary>
/// Adds a <see cref="IInterceptionBehavior"/> to the pipeline.
/// </summary>
/// <param name="interceptionBehavior">The interception behavior to add.</param>
public void Add(IInterceptionBehavior interceptionBehavior)
{
Guard.ArgumentNotNull(interceptionBehavior, "interceptionBehavior");
this.interceptionBehaviors.Add(interceptionBehavior);
}
}
到这里,看见NewInstanceWithAdditionalInterfaces方法中:
foreach (IInterceptionBehavior interceptionBehavior in activeBehaviors)
{
proxy.AddInterceptionBehavior(interceptionBehavior);
}
AddInterceptionBehavior实际调用的是InterceptionBehaviorPipeline的Add方法
但是有一个环节:InterceptionBehaviorPipeline在proxy实例中是如何实例化的?
{
internal static FieldBuilder ImplementIInterceptingProxy(TypeBuilder typeBuilder)
{
typeBuilder.AddInterfaceImplementation(typeof(IInterceptingProxy));
//定义了这个field,但在哪里newInterceptionBehaviorPipeline()的呢?
typeBuilder.DefineField(
"pipeline",
typeof(InterceptionBehaviorPipeline),
FieldAttributes.Private | FieldAttributes.InitOnly);
ImplementAddInterceptionBehavior(typeBuilder, proxyInterceptorPipelineField);
return proxyInterceptorPipelineField;
}
.......
自己做一个实验:
public class t1
{
public string s1;
public t1()
{
s1 = "xxx";
}
}
private void button4_Click(object sender, EventArgs e)
{
AppDomain domain = AppDomain.CurrentDomain;
//动态程序集
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
//动态程序集模块
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("helloWorldTypeBuilder");
//运行时创建类
TypeBuilder helloWorldTypeBuilder = moduleBuilder.DefineType("hello");
helloWorldTypeBuilder.DefineField(
"myt1",
typeof(t1),
FieldAttributes.Public | FieldAttributes.InitOnly);
Type testT1 = helloWorldTypeBuilder.CreateType();
object ins1 = Activator.CreateInstance(testT1);
string s = ((t1)testT1.GetField("myt1").GetValue(ins1)).s1;// 红色的一定是null,程序会运行时报错
MessageBox.Show(s);
}
要在动态类的构造函数中去构造myt1:
private void button4_Click(object sender, EventArgs e)
{
AppDomain domain = AppDomain.CurrentDomain;
//动态程序集
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
//动态程序集模块
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("helloWorldTypeBuilder");
//运行时创建类
TypeBuilder helloWorldTypeBuilder = moduleBuilder.DefineType("hello");
FieldBuilder myt1Field = helloWorldTypeBuilder.DefineField(
"myt1",
typeof(t1),
FieldAttributes.Public | FieldAttributes.InitOnly);
ConstructorBuilder ctorBuilder = helloWorldTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[]{typeof(string)});
ILGenerator il = ctorBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, typeof(t1).GetConstructor(Type.EmptyTypes));
il.Emit(OpCodes.Stfld, myt1Field);
il.Emit(OpCodes.Ret);
Type testT1 = helloWorldTypeBuilder.CreateType();
object ins1 = Activator.CreateInstance(testT1,new string[]{""});
string s = ((t1)testT1.GetField("myt1").GetValue(ins1)).s1;
MessageBox.Show(s);
}
这样就可以了。
你会在类InterceptingClassGenerator中发现InterceptionBehaviorPipeline的实例化:
private void AddConstructor(ConstructorInfo ctor)
{
if (!(ctor.IsPublic || ctor.IsFamily || ctor.IsFamilyOrAssembly)) return;
MethodAttributes attributes =
(ctor.Attributes
& ~MethodAttributes.ReservedMask
& ~MethodAttributes.MemberAccessMask)
| MethodAttributes.Public;
ParameterInfo[] parameters = ctor.GetParameters();
Type[] paramTypes = parameters.Select(item => item.ParameterType).ToArray();
ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(
attributes, ctor.CallingConvention, paramTypes);
for (int i = 0; i < parameters.Length; i++)
{
ctorBuilder.DefineParameter(i + 1, parameters[i].Attributes, parameters[i].Name);
}
ILGenerator il = ctorBuilder.GetILGenerator();
// Initialize pipeline field
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, InterceptionBehaviorPipelineMethods.Constructor);
il.Emit(OpCodes.Stfld, proxyInterceptionPipelineField);
// call base class construtor
il.Emit(OpCodes.Ldarg_0);
for (int i = 0; i < paramTypes.Length; ++i)
{
il.Emit(OpCodes.Ldarg, i + 1);
}
il.Emit(OpCodes.Call, ctor);
il.Emit(OpCodes.Ret);
}
AddConstructor这个方法是上面标注为蓝色的方法GenerateType中被调用:
public Type GenerateType()
{
AddMethods();
AddProperties();
AddEvents();
AddConstructors();//这里面会调用
int memberCount = 0;
HashSet<Type> implementedInterfaces = GetImplementedInterfacesSet();
foreach (var @interface in this.additionalInterfaces)
{
memberCount =
new InterfaceImplementation(this.typeBuilder, @interface, this.proxyInterceptionPipelineField, true)
.Implement(implementedInterfaces, memberCount);
}
Type result = typeBuilder.CreateType();
#if DEBUG_SAVE_GENERATED_ASSEMBLY
assemblyBuilder.Save("Unity_ILEmit_DynamicClasses.dll");
#endif
return result;
}
以上把IInterceptingProxy接口的实现说清楚了。接下来要关注第二个问题:
2、下图是如何实现的:
看这些:
类 InterceptionBehaviorPipeline 的 方法:
public IMethodReturn Invoke(IMethodInvocation input, InvokeInterceptionBehaviorDelegate target)
{
if (interceptionBehaviors.Count == 0)
{
return target(input, null);
}
int interceptorIndex = 0;
//interceptionBehaviors这个数组中正是我们定义的每一个IInterceptionBehavior实例
IMethodReturn result = interceptionBehaviors[0].Invoke(input, delegate
{
++interceptorIndex;
if (interceptorIndex < interceptionBehaviors.Count)
{
return interceptionBehaviors[interceptorIndex].Invoke;
}
else
{
return target;
}
});
return result;
}
应该是很清楚的体现了上图
那InterceptionBehaviorPipeline.Invoke在哪里被调用?
在Unity\Unity\Unity.Interception\Src\Interceptors\TypeInterceptors\VirtualMethodInterception\InterceptingClassGeneration\MethodOverride.cs
的类MethodOverride的方法CreateMethodOverride中可以找到答案:
private MethodBuilder CreateMethodOverride(MethodBuilder delegateMethod)
{
MethodAttributes attrs =
methodToOverride.Attributes & ~MethodAttributes.NewSlot & ~MethodAttributes.Abstract;
MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodToOverride.Name, attrs);
var paramMapper = new MethodOverrideParameterMapper(methodToOverride);
paramMapper.SetupParameters(methodBuilder);
methodBuilder.SetReturnType(paramMapper.GetParameterType(methodToOverride.ReturnType));
methodBuilder.SetParameters(methodParameters.Select(pi => paramMapper.GetParameterType(pi.ParameterType)).ToArray());
int paramNum = 1;
foreach (ParameterInfo pi in methodParameters)
{
methodBuilder.DefineParameter(paramNum++, pi.Attributes, pi.Name);
}
ILGenerator il = methodBuilder.GetILGenerator();
LocalBuilder methodReturn = il.DeclareLocal(typeof(IMethodReturn));
LocalBuilder ex = il.DeclareLocal(typeof(Exception));
LocalBuilder parameterArray = il.DeclareLocal(typeof(object[]));
LocalBuilder inputs = il.DeclareLocal(typeof(VirtualMethodInvocation));
// Create instance of VirtualMethodInvocation
il.Emit(OpCodes.Ldarg_0); // target object
il.Emit(OpCodes.Ldtoken, methodToOverride);
if (methodToOverride.DeclaringType.IsGenericType)
{
il.Emit(OpCodes.Ldtoken, methodToOverride.DeclaringType);
il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodForGenericFromHandle);
}
else
{
il.Emit(OpCodes.Call, MethodBaseMethods.GetMethodFromHandle); // target method
}
EmitLoadConstant(il, methodParameters.Length);
il.Emit(OpCodes.Newarr, typeof(object)); // object[] parameters
if (methodParameters.Length > 0)
{
il.Emit(OpCodes.Stloc, parameterArray);
for (int i = 0; i < methodParameters.Length; ++i)
{
il.Emit(OpCodes.Ldloc, parameterArray);
EmitLoadConstant(il, i);
EmitLoadArgument(il, i);
if (methodParameters[i].ParameterType.IsValueType || methodParameters[i].ParameterType.IsGenericParameter)
{
il.Emit(OpCodes.Box, paramMapper.GetParameterType(methodParameters[i].ParameterType));
}
else if (methodParameters[i].ParameterType.IsByRef)
{
Type elementType = paramMapper.GetElementType(methodParameters[i].ParameterType);
il.Emit(OpCodes.Ldobj, elementType);
if (elementType.IsValueType || elementType.IsGenericParameter)
{
il.Emit(OpCodes.Box, elementType);
}
}
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldloc, parameterArray);
}
il.Emit(OpCodes.Newobj, VirtualMethodInvocationMethods.VirtualMethodInvocation);
il.Emit(OpCodes.Stloc, inputs);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, proxyInterceptionPipelineField);
il.Emit(OpCodes.Ldloc, inputs);
// Put delegate reference onto the stack
il.Emit(OpCodes.Ldarg_0);
MethodInfo invokeTarget = delegateMethod;
if(delegateMethod.IsGenericMethod)
{
invokeTarget = delegateMethod.MakeGenericMethod(paramMapper.MappedGenericParameters);
}
il.Emit(OpCodes.Ldftn, invokeTarget);
il.Emit(OpCodes.Newobj, InvokeInterceptionBehaviorDelegateMethods.InvokeInterceptionBehaviorDelegate);
// And call the pipeline
il.Emit(OpCodes.Call, InterceptionBehaviorPipelineMethods.Invoke);
il.Emit(OpCodes.Stloc, methodReturn);
// Was there an exception?
Label noException = il.DefineLabel();
il.Emit(OpCodes.Ldloc, methodReturn);
il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetException, null);
il.Emit(OpCodes.Stloc, ex);
il.Emit(OpCodes.Ldloc, ex);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Ceq);
il.Emit(OpCodes.Brtrue_S, noException);
il.Emit(OpCodes.Ldloc, ex);
il.Emit(OpCodes.Throw);
il.MarkLabel(noException);
// handle return value
if (MethodHasReturnValue)
{
il.Emit(OpCodes.Ldloc, methodReturn);
il.EmitCall(OpCodes.Callvirt, IMethodReturnMethods.GetReturnValue, null);
if (ReturnType.IsValueType || ReturnType.IsGenericParameter)
{
il.Emit(OpCodes.Unbox_Any, paramMapper.GetParameterType(ReturnType));
}
else
{
il.Emit(OpCodes.Castclass, paramMapper.GetParameterType(ReturnType));
}
}
// handle byref parameters
if (methodParameters.Length > 0)
{
int outArgIndex = 0;
foreach (int parameterIndex in OutputParameterIndices)
{
// Get parameter value (the address) onto the stack)
Type elementType = paramMapper.GetElementType(methodParameters[parameterIndex].ParameterType);
EmitLoadArgument(il, parameterIndex);
// Get result of output parameter out of the results array
il.Emit(OpCodes.Ldloc, methodReturn);
il.Emit(OpCodes.Callvirt, IMethodReturnMethods.GetOutputs);
EmitLoadConstant(il, outArgIndex);
il.Emit(OpCodes.Callvirt, IListMethods.GetItem);
EmitUnboxOrCast(il, elementType);
// And store the results
il.Emit(OpCodes.Stobj, elementType);
++outArgIndex;
}
}
il.Emit(OpCodes.Ret);
return methodBuilder;
}
我们应该体会到了System.Reflection.Emit是一个奇妙的命名空间。