Esempio n. 1
0
 public MyTest(IEmit instance, IInterceptor interceptor)
 {
     this.instance    = instance;
     this.interceptor = interceptor;
 }
Esempio n. 2
0
        static void Main(string[] args)
        {
            var assemblyName = new AssemblyName("CodeArts.Emit");

            var assemblyBuilder = AppDomain.CurrentDomain
                                  .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);

            var moduleBuilder = assemblyBuilder.DefineDynamicModule("CodeArts.Module", "CodeArts.Emit.dll");

            var iEmitType = typeof(IEmit);

            var interceptorType = typeof(IInterceptor);

            var typeBuilder = moduleBuilder.DefineType("EmitProxy", TypeAttributes.Class | TypeAttributes.NotPublic, null, new Type[] { iEmitType });

            var instanceField = typeBuilder.DefineField("instance", iEmitType, FieldAttributes.Private | FieldAttributes.InitOnly);

            var interceptorField = typeBuilder.DefineField("interceptor", interceptorType, FieldAttributes.Private | FieldAttributes.InitOnly);

            var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { iEmitType, interceptorType });

            constructorBuilder.DefineParameter(1, ParameterAttributes.None, "instance");
            constructorBuilder.DefineParameter(2, ParameterAttributes.None, "interceptor");

            var ilOfCtor = constructorBuilder.GetILGenerator();

            var objectType = typeof(object);

            ilOfCtor.Emit(OpCodes.Ldarg_0);
            ilOfCtor.Emit(OpCodes.Call, objectType.GetConstructor(new Type[0]));
            ilOfCtor.Emit(OpCodes.Ldarg_0);
            ilOfCtor.Emit(OpCodes.Ldarg_1);
            ilOfCtor.Emit(OpCodes.Stfld, instanceField);
            ilOfCtor.Emit(OpCodes.Ldarg_0);
            ilOfCtor.Emit(OpCodes.Ldarg_2);
            ilOfCtor.Emit(OpCodes.Stfld, interceptorField);

            ilOfCtor.Emit(OpCodes.Ret);

            var constructorStaticBuilder = typeBuilder.DefineConstructor(MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes);

            var ilOfStaticCtor = constructorStaticBuilder.GetILGenerator();

            var invokeType  = typeof(InvokeBinder);
            var returnValue = typeof(IIntercept).GetProperty("ReturnValue");
            var invokeCtor  = invokeType.GetConstructor(new Type[] { typeof(object), typeof(MethodInfo), typeof(object[]) });

            var interceptMethod = interceptorType.GetMethod("Intercept", new Type[] { typeof(IIntercept) });

            foreach (var method in iEmitType.GetMethods())
            {
                var parameters     = method.GetParameters();
                var parameterTypes = parameters.Select(x => x.ParameterType).ToArray();
                var methodBuilder  = typeBuilder.DefineMethod(method.Name,
                                                              MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                                                              CallingConventions.Standard);

                if (method.IsGenericMethod)
                {
                    var genericArguments = method.GetGenericArguments();

                    var newGenericParameters = methodBuilder.DefineGenericParameters(genericArguments.Select(x => x.Name).ToArray());

                    foreach (var item in genericArguments.Zip(newGenericParameters, (g, t) =>
                    {
                        t.SetGenericParameterAttributes(g.GenericParameterAttributes);

                        t.SetInterfaceConstraints(g.GetGenericParameterConstraints());

                        t.SetBaseTypeConstraint(g.BaseType);

                        return(true);
                    }))
                    {
                    }
                }

                methodBuilder.SetReturnType(method.ReturnType);

                methodBuilder.SetParameters(parameterTypes);

                parameters.ForEach((p, index) =>
                {
                    methodBuilder.DefineParameter(index + 1, p.Attributes, p.Name);
                });

                var ilGen = methodBuilder.GetILGenerator();

                LocalBuilder local = method.IsGenericMethod
                    ? CreateInvokeBinder(typeBuilder, ilOfStaticCtor, ilGen, instanceField, invokeCtor, method.MakeGenericMethod(methodBuilder.GetGenericArguments()), parameterTypes)
                    : CreateInvokeBinder(typeBuilder, ilOfStaticCtor, ilGen, instanceField, invokeCtor, method, parameterTypes);

                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, interceptorField);
                ilGen.Emit(OpCodes.Ldloc, local);
                ilGen.Emit(OpCodes.Call, interceptMethod);

                if (method.ReturnType == typeof(void))
                {
                    ilGen.Emit(OpCodes.Pop);
                }
                else
                {
                    ilGen.Emit(OpCodes.Callvirt, returnValue.GetMethod);

                    if (method.ReturnType.IsValueType && !(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Nullable <>)))
                    {
                        var value = ilGen.DeclareLocal(typeof(object));

                        ilGen.Emit(OpCodes.Stloc, value);

                        ilGen.Emit(OpCodes.Ldloc, value);

                        var nullLabel = ilGen.DefineLabel();

                        ilGen.Emit(OpCodes.Ldnull);

                        ilGen.Emit(OpCodes.Ceq);

                        ilGen.Emit(OpCodes.Brfalse_S, nullLabel);

                        ilGen.Emit(OpCodes.Nop);

                        ilGen.Emit(OpCodes.Ldstr, "Interceptors failed to set a return value, or swallowed the exception thrown by the target.");

                        ilGen.Emit(OpCodes.Newobj, typeof(InvalidOperationException).GetConstructor(new Type[] { typeof(string) }));

                        ilGen.Emit(OpCodes.Throw);

                        ilGen.MarkLabel(nullLabel);

                        ilGen.Emit(OpCodes.Ldloc, value);
                    }

                    if (method.ReturnType.IsValueType || method.ReturnType.IsGenericParameter)
                    {
                        ilGen.Emit(OpCodes.Unbox_Any, method.ReturnType);
                    }
                    else
                    {
                        ilGen.Emit(OpCodes.Castclass, method.ReturnType);
                    }
                }

                ilGen.Emit(OpCodes.Ret);

                typeBuilder.DefineMethodOverride(methodBuilder, method);
            }

            ilOfStaticCtor.Emit(OpCodes.Ret);

            var type = typeBuilder.CreateType();

            assemblyBuilder.Save("CodeArts.Emit.dll");

            IEmit emit = (IEmit)Activator.CreateInstance(type, new Emit(), new Interceptor());

            emit.Test();

            var g1 = emit.TestG(new object());

            var g2 = emit.TestG(18);

            var g3 = emit.TestGConstraint(DateTimeKind.Utc);

            var i = emit.TestInt32(8);

            var v = emit.TestValueType(1);

            var c = emit.TestClas();
        }