public void TestZzz2() { var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave); var mod = asm.DefineDynamicModule("mymod", "tmp.dll", true); var type = mod.DefineType("baz", TypeAttributes.Public | TypeAttributes.Class); var meth = type.DefineMethod("go", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int) }); var document = mod.DefineDocument("TestDebug2.txt", Guid.Empty, Guid.Empty, Guid.Empty); //Expression.SymbolDocument("TestDebug2.txt"); //var di = Expression.DebugInfo(sdi, 2, 2, 2, 13); //var exp = Expression.Divide(Expression.Constant(2), Expression.Subtract(Expression.Constant(4), Expression.Constant(4))); //var block = Expression.Block(di, exp); using (var il = new GroboIL(meth)) { // nop // [] // nop // [] // ldc.i4.1 // [Int32] // brfalse ifFalse_7 // [] // nop // [] // ldarg.0 // [Int32] // br done_10 // [Int32] //ifFalse_7: // [] // nop // [] // ldarg.0 // [Int32] //done_10: // [Int32] // stloc local_0 // [] // nop // [] // ldloc local_0 // [Int32] // ret // [] // var tst = Expression.Block(Expression.DebugInfo(sdi, 6, 20, 6, 27), Expression.Constant(true)); // var iftrue = Expression.Block(Expression.DebugInfo(sdi, 10, 20, 10, 26), variable); // var iffalse = Expression.Block(Expression.DebugInfo(sdi, 14, 20, 14, 26), variable); // var exp = Expression.Condition(tst, iftrue, iffalse); // // /* // var returnTarget = Expression.Label(typeof(int)); // var returnExpression = Expression.Return(returnTarget, exp, typeof(int)); // var returnLabel = Expression.Label(returnTarget, Expression.Constant(0)); // */ // // var block = Expression.Block(typeof(int), new[] { temp }, // Expression.DebugInfo(sdi, 4, 15, 4, 16), Expression.Assign(temp, exp), Expression.DebugInfo(sdi, 17, 16, 17, 21), temp); // //var block = Expression.Block(Expression.DebugInfo(sdi, 4, 16, 17, 10), Expression.Assign(temp, exp))); // var kek = Expression.Lambda(block, variable); il.MarkSequencePoint(document, 4, 15, 4, 16); il.Nop(); il.Nop(); il.Ldc_I4(1); il.MarkSequencePoint(document, 6, 20, 6, 27); var brFalse = il.DefineLabel("brFalse"); il.Brfalse(brFalse); il.MarkSequencePoint(document, 10, 20, 10, 26); il.Nop(); il.Ldarg(0); il.Ldc_I4(100); il.Add(); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); il.MarkSequencePoint(document, 14, 20, 14, 26); il.MarkLabel(brFalse); il.Nop(); il.Ldarg(0); il.Ldc_I4(10); il.Add(); il.MarkLabel(doneLabel); il.MarkSequencePoint(document, 16, 16, 16, 21); var local = il.DeclareLocal(typeof(int)); il.Stloc(local); il.Nop(); il.MarkSequencePoint(document, 17, 16, 17, 21); il.Ldloc(local); il.Ret(); } var newtype = type.CreateType(); asm.Save("tmp.dll"); newtype.GetMethod("go").Invoke(null, new object[] { 0 }); //meth.Invoke(null, new object[0]); //lambda.DynamicInvoke(new object[0]); Console.WriteLine(" "); }
/// <summary> /// Builds Proxy Type that implement an interface, and proxy calls to defined with attribute /// methods via defined intercepting handlers /// </summary> /// <param name="interface">Type to wrap</param> /// <param name="implementation"> /// Type providing interface implementation, intercepting attributes are read from this type /// </param> /// <returns> /// Proxy type with constructor accepting object implementing @interface and intercepting /// handlers as parameters /// </returns> public static Type CreateInterfaceProxy(Type @interface, Type implementation) { Contract.Ensures(Contract.Result <Type>() != null); if ([email protected]) { throw new ArgumentException($"{nameof(@interface)} ({@interface.FullName}) is not an interface."); } if ([email protected](implementation)) { throw new ArgumentException($"{nameof(@interface)} ({@interface.FullName}) is not assignable from {nameof(implementation)} ({implementation.FullName})"); } var typeName = $"{@interface.Assembly.GetName().Name}.v{@interface.Assembly.GetName().Version}.{@interface.FullName}"; var typeBuilder = ModuleBuilder.DefineType($"InterceptorProxy_{typeName}_{Guid.NewGuid().ToString("N")}", TypeAttributes.Class | TypeAttributes.Public); typeBuilder.AddInterfaceImplementation(SetupGenericClassArguments(@interface, typeBuilder)); var methods = new List <MethodPair>(); AddMethodPairsToList(methods, @interface, implementation); var methodInterceptors = new Dictionary <MethodInfo, Type[]>(); var interceptorFields = new Dictionary <Type, FieldInfo>(); var methodsCount = methods.Count; var attributesHashSet = new HashSet <Type>(); for (var i = 0; i < methodsCount; i++) { var method = methods[i]; var interfaceMethod = method.InterfaceMethod; var typeMethod = method.TargetMethod; var attributeTypes = Attribute.GetCustomAttributes(typeMethod, typeof(InterceptorAttribute), true) .OrderBy(a => ((InterceptorAttribute)a).Order).Select(a => ((InterceptorAttribute)a).InterceptionHandlerType).ToArray(); for (int j = 0; j < attributeTypes.Length; j++) { if (!typeof(IInterceptionHandler).IsAssignableFrom(attributeTypes[j])) { throw new InvalidOperationException($"Interception handler type should implement {nameof(IInterceptionHandler)} interface"); } } attributesHashSet.UnionWith(attributeTypes); methodInterceptors.Add(interfaceMethod, attributeTypes); } var baseConstructorInfo = typeof(object).GetConstructor(Type.EmptyTypes); var intercpetionHandlerType = typeof(IInterceptionHandler); var genericInterceptionAction = intercpetionHandlerType.GetMethods().Single(i => i.Name == "InterceptingAction" && i.ReturnType != typeof(void)); var voidInterceptionAction = intercpetionHandlerType.GetMethods().Single(i => i.Name == "InterceptingAction" && i.ReturnType == typeof(void)); var att = attributesHashSet.ToList(); att.Insert(0, implementation); var paramArray = att.ToArray(); var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, paramArray); var concrete = typeBuilder.DefineField("Concrete", @interface, FieldAttributes.Public); for (int i = 1; i < paramArray.Length; i++) { var at = paramArray[i]; interceptorFields.Add(at, typeBuilder.DefineField(at.Name, intercpetionHandlerType, FieldAttributes.Public)); } GroboIL il; using (il = new GroboIL(constructorBuilder)) { il.Ldarg(0); il.Call(baseConstructorInfo); il.Nop(); // set concrete il.Ldarg(0); il.Ldarg(1); il.Stfld(concrete); // set injected interceptionHandlers for (var i = 1; i < paramArray.Length; i++) { il.Ldarg(0); il.Ldarg(i + 1); il.Stfld(interceptorFields[paramArray[i]]); } il.Ret(); LogIlCode(il); } for (var i = 0; i < methodsCount; i++) { var interfaceMethod = methods[i].InterfaceMethod; if (interfaceMethod.IsGenericMethod) { interfaceMethod = interfaceMethod.GetGenericMethodDefinition(); } DefineMethodOverride(typeBuilder, interfaceMethod, methodInterceptors, interceptorFields, genericInterceptionAction, voidInterceptionAction, concrete); } return(typeBuilder.CreateTypeInfo().AsType()); }
public void TestZzz() { var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("foo"), AssemblyBuilderAccess.RunAndSave); var mod = asm.DefineDynamicModule("mymod", "tmp.dll", true); var type = mod.DefineType("baz", TypeAttributes.Public | TypeAttributes.Class); var meth = type.DefineMethod("go", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new[] { typeof(int) }); var document = mod.DefineDocument("TestDebug2.txt", Guid.Empty, Guid.Empty, Guid.Empty); //Expression.SymbolDocument("TestDebug2.txt"); meth.DefineParameter(1, ParameterAttributes.In, "$x"); //var di = Expression.DebugInfo(sdi, 2, 2, 2, 13); //var exp = Expression.Divide(Expression.Constant(2), Expression.Subtract(Expression.Constant(4), Expression.Constant(4))); //var block = Expression.Block(di, exp); using (var il = new GroboIL(meth)) { // var tst = Expression.Block(Expression.DebugInfo(sdi, 6, 20, 6, 27), Expression.Equal(variable, zero)); // var iftrue = Expression.Block(Expression.DebugInfo(sdi, 10, 20, 10, 26), Expression.Add(variable, two)); // var iffalse = Expression.Block(Expression.DebugInfo(sdi, 14, 20, 14, 26), Expression.Divide(variable, two)); // var exp = Expression.Condition(tst, iftrue, iffalse); // var block = Expression.Block(Expression.DebugInfo(sdi, 4, 16, 15, 10), exp); // nop // [] // nop // [] // ldarg.0 // [Int32] // ldc.i4.0 // [Int32, Int32] // ceq // [Int32] // brfalse ifFalse_5 // [] // nop // [] // ldarg.0 // [Int32] // ldc.i4.2 // [Int32, Int32] // add // [Int32] // br done_8 // [Int32] //ifFalse_5: // [] // nop // [] // ldarg.0 // [Int32] // ldc.i4.2 // [Int32, Int32] // div // [Int32] //done_8: // [Int32] // ret // [] il.MarkSequencePoint(document, 3, 9, 3, 15); il.Nop(); il.MarkSequencePoint(document, 4, 13, 4, 19); il.Nop(); il.Ldarg(0); il.Ldc_I4(0); il.Ceq(); var label = il.DefineLabel("ifFalse"); il.Brfalse(label); il.MarkSequencePoint(document, 7, 13, 7, 19); il.Nop(); il.Ldarg(0); il.Ldc_I4(2); il.Add(); var doneLabel = il.DefineLabel("done"); il.Br(doneLabel); il.MarkLabel(label); il.MarkSequencePoint(document, 10, 13, 10, 19); il.Nop(); il.Ldarg(0); il.Ldc_I4(2); il.Mul(); il.MarkLabel(doneLabel); il.MarkSequencePoint(document, 12, 5, 12, 6); il.Nop(); il.Ret(); } var newtype = type.CreateType(); asm.Save("tmp.dll"); newtype.GetMethod("go").Invoke(null, new object[] { 0 }); //meth.Invoke(null, new object[0]); //lambda.DynamicInvoke(new object[0]); Console.WriteLine(" "); }
private static void DefineMethodOverrideWithInterception(TypeBuilder typeBuilder, MethodBuilder methodBuilder, MethodInfo overridedMethod, Dictionary <Type, FieldInfo> interceptorFields, MethodInfo genericInterceptionAction, MethodInfo voidInterceptionAction, FieldBuilder concreteInstance, ParameterInfo[] methodParams, Type[] genericParameterTypes, Type[] interceptors) { var @delegate = GenerateOverloadedMethodDelegate(overridedMethod, typeBuilder, concreteInstance); for (var i = 0; i < interceptors.Length; i++) { var interceptor = interceptors[i]; @delegate = DefineMethodInterceptingDelegate(typeBuilder, overridedMethod, interceptorFields, genericInterceptionAction, voidInterceptionAction, genericParameterTypes, @delegate, i, interceptor); } using (var il = new GroboIL(methodBuilder)) { var paramInfoType = typeof(ParamInfo); var paramsInfoType = typeof(ParamInfo[]); var paramsInfo = il.DeclareLocal(paramsInfoType); var paramInfo = il.DeclareLocal(paramInfoType); il.Nop(); il.Ldc_I4(methodParams.Length); il.Newarr(typeof(ParamInfo)); il.Stloc(paramsInfo); var paramInfoConstructor = paramInfoType.GetConstructor(new[] { typeof(string), typeof(Type), typeof(bool), typeof(bool) }); var paramInfoValueSetter = paramInfoType.GetProperty("Value").GetSetMethod(); var getTypeMethod = typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }); var idx = 0; foreach (var parameter in methodParams) { // load array at index il.Ldloc(paramsInfo); il.Ldc_I4(idx++); // Load ParamInfo.Name il.Ldstr(parameter.Name); // Load ParamInfo.Type if (parameter.IsOut || parameter.ParameterType.IsByRef) { il.Ldtoken(parameter.ParameterType.GetElementType()); } else { il.Ldtoken(parameter.ParameterType); } il.Call(getTypeMethod); // Load ParamInfo.IsByRef if (parameter.ParameterType.IsByRef) { il.Ldc_I4(1); } else { il.Ldc_I4(0); } // Load ParamInfo.IsOut if (parameter.IsOut) { il.Ldc_I4(1); } else { il.Ldc_I4(0); } // instantiate ParamInfo il.Newobj(paramInfoConstructor); il.Stloc(paramInfo); // Set ParamInfo.Value il.Ldloc(paramInfo); il.Ldarg(parameter.Position + 1); if (parameter.IsOut || parameter.ParameterType.IsByRef) { il.Ldobj(parameter.ParameterType.GetElementType()); if (parameter.ParameterType.GetElementType().IsValueType || parameter.ParameterType.GetElementType().IsGenericParameter) { il.Box(parameter.ParameterType.GetElementType()); } } else { if (parameter.ParameterType.IsValueType || parameter.ParameterType.IsGenericParameter) { il.Box(parameter.ParameterType); } } il.Call(paramInfoValueSetter); il.Nop(); // push to array il.Ldloc(paramInfo); il.Stelem(paramInfoType); } il.Ldarg(0); il.Ldloc(paramsInfo); if (overridedMethod.IsGenericMethodDefinition) { il.Call(@delegate.MakeGenericMethod(genericParameterTypes)); } else { il.Call(@delegate); } idx = 1; var paramInfoValueGetter = paramInfoType.GetProperty("Value").GetGetMethod(); foreach (var parameter in methodParams) { if (parameter.IsOut || parameter.ParameterType.IsByRef) { il.Ldarg(idx); il.Ldloc(paramsInfo); il.Ldc_I4(idx - 1); il.Ldelem(paramInfoType); il.Call(paramInfoValueGetter); if (parameter.ParameterType.GetElementType().IsValueType) { il.Unbox_Any(parameter.ParameterType.GetElementType()); } il.Stobj(parameter.ParameterType.GetElementType()); } idx++; } il.Ret(); LogIlCode(il); } }