Emit实现简单的Aop
最近在研究Emit,发现其实Emit很简单,但是IL很难,还好以前学习过汇编研究了很久才把指令搞清楚.
首先就来看看需要实现一个简单的Aop需要的类:
首先是拦截器,这里仿照Wcf的IParameterInspector定义了一个简单的接口,不支持ref和out参数。
/// <summary>
/// 拦截器接口
/// </summary>
public interface IInterceptor
{
/// <summary>
/// 方法调用前
/// </summary>
/// <param name="operationName">方法名</param>
/// <param name="inputs">参数</param>
/// <returns>状态对象,用于调用后传入</returns>
object BeforeCall(string operationName, object[] inputs);
/// <summary>
/// 方法调用后
/// </summary>
/// <param name="operationName">方法名</param>
/// <param name="returnValue">结果</param>
/// <param name="correlationState">状态对象</param>
void AfterCall(string operationName, object returnValue, object correlationState);
}
创建一个简单的实现来测试
public class StandardInterceptor : IInterceptor
{
public object BeforeCall(string operationName, object[] inputs)
{
Console.WriteLine("Before call :{0}", operationName);
return null;
}
public void AfterCall(string operationName, object returnValue, object correlationState)
{
Console.WriteLine("After call :{0} resule: {1}", operationName, returnValue??"Null");
}
}
简单工厂模式定义拦截器工厂
public class DefaultInterceptorFactory
{
public static IInterceptor Create(Type type)
{
return new StandardInterceptor();
}
}
接下来定义一个测试类型
public class Animal
{
public virtual string Speak(string msg)
{
Console.WriteLine("Animal.Speak:{0}", msg);
return msg;
}
public virtual void Speak()
{
Console.WriteLine("Animal.Speak");
}
}
Aop采用继承的方式,通过Emit构造子类,为了方便先用程序将子类编写好方便对比IL调试
public class AnimalAop : Animal
{
private readonly IInterceptor _inspector;
public AnimalAop()
{
_inspector = DefaultInterceptorFactory.Create(typeof(Animal));
}
public override void Speak()
{
object correlationState = _inspector.BeforeCall("Speak", null);
base.Speak();
object result = null;
_inspector.AfterCall("Speak", result, correlationState);
}
public override string Speak(string msg)
{
object correlationState = _inspector.BeforeCall("Speak", new object[] { msg });
var result = base.Speak(msg);
_inspector.AfterCall("Speak", result, correlationState);
return result;
}
}
好了,准备工作完成了,接下来就是如何来用Emit生成这个代理对象
依然是简单工厂DefaultProxyBuilder
public static T CreateProxy<T>()
{
Type classType = typeof(T);
string name = classType.Namespace + ".Aop";
string fileName = name + ".dll";
AssemblyName assemblyName = new AssemblyName(name);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, fileName);
var aopType = BulidType(classType, moduleBuilder);
assemblyBuilder.Save(fileName);
return (T)Activator.CreateInstance(aopType);
}
构建类包含了
1 构建类型
//定义类型
var typeBuilder = moduleBuilder.DefineType(className,
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
classType);
2 构建拦截器字段_inspector
var inspectorFieldBuilder = typeBuilder.DefineField("_inspector", typeof (IInterceptor),
FieldAttributes.Private | FieldAttributes.InitOnly);
3 构建构造函数 初始化inspector
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis,
Type.EmptyTypes);
var il = ctorBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, classType.GetConstructor(Type.EmptyTypes));//调用base的默认ctor
il.Emit(OpCodes.Ldarg_0);
//将typeof(classType)压入计算堆
il.Emit(OpCodes.Ldtoken, classType);
il.Emit(OpCodes.Call, typeof (Type).GetMethod("GetTypeFromHandle", new[] {typeof (RuntimeTypeHandle)}));
//调用DefaultInterceptorFactory.Create(type)
il.Emit(OpCodes.Call, typeof (DefaultInterceptorFactory).GetMethod("Create", new[] {typeof (Type)}));
//将结果保存到字段_inspector
il.Emit(OpCodes.Stfld, inspectorFieldBuilder);
il.Emit(OpCodes.Ret);
4 构建方法 使用拦截器_inspector
首先得到父类的methodInfo 获取必要的信息
var parameterInfos = methodInfo.GetParameters();
var parameterTypes = parameterInfos.Select(p => p.ParameterType).ToArray();
var parameterLength = parameterTypes.Length;
var hasResult = methodInfo.ReturnType != VoidType;
var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Final |
MethodAttributes.Virtual
, methodInfo.ReturnType
, parameterTypes);
定义局部变量 这个顺序很重要 下面的操作要使用到
var il = methodBuilder.GetILGenerator();
//局部变量
il.DeclareLocal(typeof (object)); //correlationState
il.DeclareLocal(typeof (object)); //result
il.DeclareLocal(typeof (object[])); //parameters
首先是调用BeforeCall
//BeforeCall(string operationName, object[] inputs);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数operationName
if (parameterLength == 0)//判断方法参数长度
{
il.Emit(OpCodes.Ldnull);//null -> 参数 inputs
}
else
{
//创建new object[parameterLength];
il.Emit(OpCodes.Ldc_I4, parameterLength);
il.Emit(OpCodes.Newarr, typeof(Object));
il.Emit(OpCodes.Stloc_2);//压入局部变量2 parameters
for (int i = 0, j = 1; i < parameterLength; i++, j++)
{
//object[i] = arg[j]
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ldarg, j);
if (parameterTypes[i].IsValueType) il.Emit(OpCodes.Box, parameterTypes[i]);//对值类型装箱
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldloc_2);//取出局部变量2 parameters-> 参数 inputs
}
il.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("BeforeCall"));//调用BeforeCall
il.Emit(OpCodes.Stloc_0);//建返回压入局部变量0 correlationState
接下来调用base的方法
//Call methodInfo
il.Emit(OpCodes.Ldarg_0);
//获取参数表
for (int i = 1, length = parameterLength + 1; i < length; i++)
{
il.Emit(OpCodes.Ldarg_S, i);
}
il.Emit(OpCodes.Call, methodInfo);
//将返回值压入 局部变量1result void就压入null
if (!hasResult) il.Emit(OpCodes.Ldnull);
else if (methodInfo.ReturnType.IsValueType) il.Emit(OpCodes.Box, methodInfo.ReturnType);//对值类型装箱
il.Emit(OpCodes.Stloc_1);
下面调用AfterCall
//AfterCall(string operationName, object returnValue, object correlationState);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数 operationName
il.Emit(OpCodes.Ldloc_1);//局部变量1 result -> 参数 returnValue
il.Emit(OpCodes.Ldloc_0);// 局部变量0 correlationState -> 参数 correlationState
il.Emit(OpCodes.Callvirt, typeof (IInterceptor).GetMethod("AfterCall"));
最后是返回
//result
if (!hasResult)
{
il.Emit(OpCodes.Ret);
return;
}
il.Emit(OpCodes.Ldloc_1);//非void取出局部变量1 result
if (methodInfo.ReturnType.IsValueType) il.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);//对值类型拆箱
il.Emit(OpCodes.Ret);
完成实现如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public static class DefaultProxyBuilder
{
private static readonly Type VoidType = Type.GetType("System.Void");
public static T CreateProxy<T>()
{
Type classType = typeof(T);
string name = classType.Namespace + ".Aop";
string fileName = name + ".dll";
var assemblyName = new AssemblyName(name);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, fileName);
var aopType = BulidType(classType, moduleBuilder);
assemblyBuilder.Save(fileName);
return (T)Activator.CreateInstance(aopType);
}
private static Type BulidType(Type classType, ModuleBuilder moduleBuilder)
{
string className = classType.Name + "_Proxy";
//定义类型
var typeBuilder = moduleBuilder.DefineType(className,
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
classType);
//定义字段 _inspector
var inspectorFieldBuilder = typeBuilder.DefineField("_inspector", typeof(IInterceptor),
FieldAttributes.Private | FieldAttributes.InitOnly);
//构造函数
BuildCtor(classType, inspectorFieldBuilder, typeBuilder);
//构造方法
BuildMethod(classType, inspectorFieldBuilder, typeBuilder);
Type aopType = typeBuilder.CreateType();
return aopType;
}
private static void BuildMethod(Type classType, FieldBuilder inspectorFieldBuilder, TypeBuilder typeBuilder)
{
var methodInfos = classType.GetMethods();
foreach (var methodInfo in methodInfos)
{
if (!methodInfo.IsVirtual && !methodInfo.IsAbstract) continue;
if (methodInfo.Name == "ToString") continue;
if (methodInfo.Name == "GetHashCode") continue;
if (methodInfo.Name == "Equals") continue;
var parameterInfos = methodInfo.GetParameters();
var parameterTypes = parameterInfos.Select(p => p.ParameterType).ToArray();
var parameterLength = parameterTypes.Length;
var hasResult = methodInfo.ReturnType != VoidType;
var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name,
MethodAttributes.Public | MethodAttributes.Final |
MethodAttributes.Virtual
, methodInfo.ReturnType
, parameterTypes);
var il = methodBuilder.GetILGenerator();
//局部变量
il.DeclareLocal(typeof(object)); //correlationState
il.DeclareLocal(typeof(object)); //result
il.DeclareLocal(typeof(object[])); //parameters
//BeforeCall(string operationName, object[] inputs);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数operationName
if (parameterLength == 0)//判断方法参数长度
{
il.Emit(OpCodes.Ldnull);//null -> 参数 inputs
}
else
{
//创建new object[parameterLength];
il.Emit(OpCodes.Ldc_I4, parameterLength);
il.Emit(OpCodes.Newarr, typeof(Object));
il.Emit(OpCodes.Stloc_2);//压入局部变量2 parameters
for (int i = 0, j = 1; i < parameterLength; i++, j++)
{
//object[i] = arg[j]
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Ldc_I4, 0);
il.Emit(OpCodes.Ldarg, j);
if (parameterTypes[i].IsValueType) il.Emit(OpCodes.Box, parameterTypes[i]);//对值类型装箱
il.Emit(OpCodes.Stelem_Ref);
}
il.Emit(OpCodes.Ldloc_2);//取出局部变量2 parameters-> 参数 inputs
}
il.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("BeforeCall"));//调用BeforeCall
il.Emit(OpCodes.Stloc_0);//建返回压入局部变量0 correlationState
//Call methodInfo
il.Emit(OpCodes.Ldarg_0);
//获取参数表
for (int i = 1, length = parameterLength + 1; i < length; i++)
{
il.Emit(OpCodes.Ldarg_S, i);
}
il.Emit(OpCodes.Call, methodInfo);
//将返回值压入 局部变量1result void就压入null
if (!hasResult) il.Emit(OpCodes.Ldnull);
else if (methodInfo.ReturnType.IsValueType) il.Emit(OpCodes.Box, methodInfo.ReturnType);//对值类型装箱
il.Emit(OpCodes.Stloc_1);
//AfterCall(string operationName, object returnValue, object correlationState);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数 operationName
il.Emit(OpCodes.Ldloc_1);//局部变量1 result
il.Emit(OpCodes.Ldloc_0);// 局部变量0 correlationState
il.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("AfterCall"));
//result
if (!hasResult)
{
il.Emit(OpCodes.Ret);
return;
}
il.Emit(OpCodes.Ldloc_1);//非void取出局部变量1 result
if (methodInfo.ReturnType.IsValueType) il.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);//对值类型拆箱
il.Emit(OpCodes.Ret);
}
}
private static void BuildCtor(Type classType, FieldBuilder inspectorFieldBuilder, TypeBuilder typeBuilder)
{
{
var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis,
Type.EmptyTypes);
var il = ctorBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, classType.GetConstructor(Type.EmptyTypes));//调用base的默认ctor
il.Emit(OpCodes.Ldarg_0);
//将typeof(classType)压入计算堆
il.Emit(OpCodes.Ldtoken, classType);
il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));
//调用DefaultInterceptorFactory.Create(type)
il.Emit(OpCodes.Call, typeof(DefaultInterceptorFactory).GetMethod("Create", new[] { typeof(Type) }));
//将结果保存到字段_inspector
il.Emit(OpCodes.Stfld, inspectorFieldBuilder);
il.Emit(OpCodes.Ret);
}
}
}
测试一下:
static void Main(string[] args)
{
Animal animal = DefaultProxyBuilder.CreateProxy<Animal>();
animal.Speak();
Console.WriteLine();
animal.Speak("Hello");
}
打印结果:
Before call :Speak
Animal.Speak
After call :Speak resule: Null
Before call :Speak
Animal.Speak:Hello
After call :Speak resule: Hello