• 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







  • 相关阅读:
    使用IntelliJ IDEA配置Tomcat(入门)
    关于hive异常:Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStor
    完整过程解决 ERROR 1045 (28000): Access denied for user 'mysql'@'localhost' (using password: NO)
    Hadoop伪分布式配置
    Spark_scala_Maven项目创建
    Spark-WordCount
    tesseract-ocr的安装及使用
    解决selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in P
    python第三方库资源
    kafka伪分布式配置
  • 原文地址:https://www.cnblogs.com/kiminozo/p/2291148.html
Copyright © 2020-2023  润新知