Guest User

Generating a proxy via Reflection.Emit

a guest
May 4th, 2011
657
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.87 KB | None | 0 0
  1. // The proxy generator, I assume that the error is buried along the lines emitting the IL code
  2.     public static class ProxyGenerator
  3.     {
  4.         public static T Create<T>(object obj, IInterception interception)
  5.         {
  6.             Type type = obj.GetType();
  7.  
  8.             TypeBuilder proxy = DefineProxy(type);
  9.  
  10.             FieldBuilder wrappedField = DefinePrivateField(proxy, "wrappedObject", type);
  11.             FieldBuilder interceptionField = DefinePrivateField(proxy, "interception", interception.GetType());
  12.  
  13.             DefineConstructor(proxy, wrappedField, interceptionField);
  14.             DefineInterfaceMethods(type, proxy, wrappedField, interceptionField);
  15.  
  16.             return (T) Activator.CreateInstance(proxy.CreateType(), obj, interception);
  17.         }
  18.  
  19.         private static TypeBuilder DefineProxy(Type type)
  20.         {
  21.             var assemblyName = new AssemblyName {Name = "GeneratedProxyAssembly"};
  22.             AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
  23.                 assemblyName, AssemblyBuilderAccess.Run);
  24.  
  25.             ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("GeneratedProxyModule");
  26.  
  27.             return moduleBuilder.DefineType(
  28.                 type.Name + "Proxy",
  29.                 type.Attributes,
  30.                 typeof (object),
  31.                 type.GetInterfaces());
  32.         }
  33.  
  34.         private static FieldBuilder DefinePrivateField(TypeBuilder typeBuilder, string fieldName, Type fieldType)
  35.         {
  36.             return typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Private);
  37.         }
  38.  
  39.         private static void DefineConstructor(TypeBuilder typeBuilder, params FieldBuilder[] parameters)
  40.         {
  41.             ConstructorBuilder ctor = typeBuilder.DefineConstructor(
  42.                 MethodAttributes.Public, CallingConventions.Standard, parameters.Select(f => f.FieldType).ToArray());
  43.  
  44.             // Emit constructor
  45.             ILGenerator g = ctor.GetILGenerator();
  46.  
  47.             // Load "this" pointer and call base constructor
  48.             g.Emit(OpCodes.Ldarg_0);
  49.             g.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));
  50.  
  51.             // Store parameters in private fields
  52.             for (int i = 0; i < parameters.Length; i++)
  53.             {
  54.                 // Load "this" pointer and parameter and store paramater in private field
  55.                 g.Emit(OpCodes.Ldarg_0);
  56.                 g.Emit(OpCodes.Ldarg, i + 1);
  57.                 g.Emit(OpCodes.Stfld, parameters[i]);
  58.             }
  59.  
  60.             // Return
  61.             g.Emit(OpCodes.Ret);
  62.         }
  63.  
  64.         private static void DefineInterfaceMethods(Type type, TypeBuilder proxy, FieldInfo wrappedField, FieldInfo interceptionField)
  65.         {
  66.             // Loop through all interface methods
  67.             foreach (MethodInfo interfaceMethod in type.GetInterfaces().SelectMany(i => i.GetMethods()))
  68.             {
  69.                 MethodInfo method = type.GetMethod(interfaceMethod.Name);
  70.  
  71.                 MethodBuilder methodBuilder = proxy.DefineMethod(
  72.                     method.Name,
  73.                     method.Attributes,
  74.                     method.ReturnType,
  75.                     method.GetParameters().Select(p => p.ParameterType).ToArray());
  76.  
  77.                 // Emit method
  78.                 ILGenerator g = methodBuilder.GetILGenerator();
  79.  
  80.                 // Intercept before
  81.                 EmitMethodCallOnMember(g, interceptionField, "Before", false);
  82.  
  83.                 // Delegate method call
  84.                 EmitMethodCallOnMember(g, wrappedField, method.Name, true);
  85.  
  86.                 // Intercept before
  87.                 EmitMethodCallOnMember(g, interceptionField, "After", false);
  88.  
  89.                 // Return
  90.                 g.Emit(OpCodes.Ret);
  91.             }
  92.         }
  93.  
  94.         private static void EmitMethodCallOnMember(ILGenerator g, FieldInfo field, string methodName, bool delegateParameters)
  95.         {
  96.             // Load "this" pointer to get address of field
  97.             g.Emit(OpCodes.Ldarg_0);
  98.             g.Emit(OpCodes.Ldflda, field);
  99.  
  100.             MethodInfo method = field.FieldType.GetMethod(methodName);
  101.             if (delegateParameters)
  102.             {
  103.                 // Load method parameters
  104.                 for (int i = 0; i < method.GetParameters().Length; i++)
  105.                 {
  106.                     g.Emit(OpCodes.Ldarg, i + 1);
  107.                 }
  108.             }
  109.  
  110.             // Emit call
  111.             g.Emit(OpCodes.Call, method);
  112.         }
  113.     }
  114.  
  115. // Some infrastructure
  116.     public interface IInterception
  117.     {
  118.         void Before();
  119.         void After();
  120.     }
  121.  
  122.     public class LogInterception : IInterception
  123.     {
  124.         public void Before()
  125.         {
  126.             Console.WriteLine("Before ... ");
  127.         }
  128.  
  129.         public void After()
  130.         {
  131.             Console.WriteLine("... After");
  132.         }
  133.     }
  134.  
  135.     public interface ITest
  136.     {
  137.         string DoSomething(string s1, string s2);
  138.     }
  139.  
  140.     public class Test : ITest
  141.     {
  142.         public string DoSomething(string s1, string s2)
  143.         {
  144.             Console.WriteLine("... doing something ...");
  145.             return s1 + s2;
  146.         }
  147.     }
  148.  
  149. // The test program, expected output is down below
  150.  
  151.     internal class Program
  152.     {
  153.         internal static void Main(string[] args)
  154.         {
  155.             var test = new Test();
  156.             var proxy = ProxyGenerator.Create<ITest>(test, new LogInterception());
  157.  
  158.             Console.WriteLine(test.DoSomething("Hello", " World"));
  159.             Console.WriteLine("----------------------------------------");
  160.             Console.WriteLine(proxy.DoSomething("Hello", " World"));
  161.  
  162.             Console.ReadKey();
  163.         }
  164.     }
  165.  
  166.  
  167. // The output
  168.  
  169. // ... doing something ...
  170. // Hello World
  171. // ----------------------------------------
  172. // Before ...
  173. // ... doing something ...
  174. // ... After
  175. // Hello World
Advertisement
Add Comment
Please, Sign In to add comment