The foreword 0.

On top: Thinking without Language Boundaries: An introduction to AOP in Java using CGLIb

As part 4, we review emit, a common dynamic weaving implementation in CSharp

The content is arranged as follows:

  • emit aop demo
  • Norns.Urd



1. emit aop demo

1.1 introduce emit

Emit is a low-level implementation of functionality similar to ASM in Java,

But instead of converting Java bytecode, you generate DOTnet IL code,

The generated IL code is compiled directly into memory by the built-in JIT compiler.

Official documentation

Emit is a familiar API for many of you, and you will think of it for almost anything you do dynamically.



We can use EMIT to achieve exactly the same dynamic AOP effects as cglib in Java in the previous post, so the language is really just a tool, how to play is up to the person playing the tool, demo below.

1.2 the demo

code

1.2.1 Simple implementation of ProxyGenerator

public abstract class MethodInterceptor { public abstract object Invoke(object instance, MethodInfo methodInfo, object[] parameters, object returnValue); }  public static class ProxyGenerator { private static ModuleBuilder moduleBuilder; private static MethodInfo getMethodMethod = typeof(MethodBase).GetMethod("GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) }); private static MethodInfo invoke = typeof(MethodInterceptor).GetMethod("Invoke"); static ProxyGenerator() { var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("EmitAopDemoTest"), AssemblyBuilderAccess.RunAndCollect); moduleBuilder = asmBuilder.DefineDynamicModule("Proxy"); } public static T Generate<T>(Type methodInterceptorType) { var proxyType = GenerateProxyType(typeof(T), methodInterceptorType); return (T)Activator.CreateInstance(proxyType); } public static Type GenerateProxyType(Type type, Type methodInterceptorType) { var typeBuilder = moduleBuilder.DefineType($"{type.Name}Proxy", TypeAttributes.Class | TypeAttributes.Public, type); foreach (var m in type.GetTypeInfo().DeclaredMethods) { var ps = m.GetParameters().Select(i => i.ParameterType).ToArray(); var newM = typeBuilder.DefineMethod(m.Name, MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, m.CallingConvention, m.ReturnType, ps); CreateProxyMethod(methodInterceptorType, m, ps, newM); typeBuilder.DefineMethodOverride(newM, m); } return typeBuilder.CreateType(); } private static void CreateProxyMethod(Type methodInterceptorType, MethodInfo m, Type[] ps, MethodBuilder newM) { var il = newM.GetILGenerator(); var argsLocal = il.DeclareLocal(typeof(object[])); var returnLocal = il.DeclareLocal(typeof(object)); Emit(opcodes.ldc_i4, ps.length); // Emit(opcodes.ldc_i4, ps.length); il.Emit(OpCodes.Newarr, typeof(object)); for (var i = 0; i < ps.Length; i++) { il.Emit(OpCodes.Dup); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); il.Emit(OpCodes.Box, ps[i]); il.Emit(OpCodes.Stelem_Ref); } il.Emit(OpCodes.Stloc, argsLocal); // Call the propped method il.Emit(opcodes.ldarg, 0); // load this for (var i = 0; i < ps.Length; i++) { il.Emit(OpCodes.Ldarg, i + 1); } il.Emit(OpCodes.Call, m); il.Emit(OpCodes.Box, newM.ReturnType); il.Emit(OpCodes.Stloc, returnLocal); . / / method is called after the interceptor il Emit (OpCodes. Newobj, methodInterceptorType GetConstructors (). The First ()); il.Emit(OpCodes.Ldarg, 0); Emit(opcodes.ldtoken, m); // Emit(opcodes.ldtoken, m); il.Emit(OpCodes.Call, getMethodMethod); il.Emit(OpCodes.Castclass, typeof(MethodInfo)); il.Emit(OpCodes.Ldloc, argsLocal); il.Emit(OpCodes.Ldloc, returnLocal); il.Emit(OpCodes.Callvirt, invoke); il.Emit(OpCodes.Stloc, returnLocal); // return il.Emit(OpCodes.Ldloc, returnLocal); il.Emit(OpCodes.Unbox_Any, newM.ReturnType); il.Emit(OpCodes.Ret); }}Copy the code

1.2.2 Test

internal class Program { private static void Main(string[] args) { RealClass proxy = ProxyGenerator.Generate<RealClass>(typeof(AddOneInterceptor)); var i = 5; var j = 10; Console.WriteLine($"{i} + {j} = {(i + j)}, but proxy is {proxy.Add(i, j)}"); }}Copy the code

Results:

5 + 10 = 15, but proxy is 16
Copy the code

2. Norns.Urd

At this point,

This series has covered all of the AOP implementations,

The static and dynamic weaving methods of AOP are introduced with cSHARP platform as an example.

The thought – free programming language boundary is expressed in Java Cglib.

Finally, I would like to introduce my current project norns. Urd Github: github.com/fs7744/Norn…

Norns.Urd is a lightweight AOP framework that implements dynamic proxies based on EMIT.

The version is based on Net Standard 2.0. so which.net versions work you know. The purpose of completing this framework is primarily personal:

  • Both static and dynamic AOP are implemented once
  • If YOU don’t implement DI, how do you integrate AOP framework implementations with other existing DI frameworks
  • How does an AOP make both sync and Async methods compatible and leave implementation options entirely up to the user

Hope this library can have some small effect on you, open source is not easy, you can give a star is very nice

Hope to see you do code farming do happy.