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);

 

完成实现如下:

View Code
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







posted @ 2011-12-17 16:03  kiminozo  阅读(3430)  评论(6编辑  收藏  举报