예제 #1
0
        public static object Bake(Type bakeInterface, Type bakeImpl, out object impl)
        {
            var info        = new BakeInfo();
            var typeBuilder = CreateType(info, bakeInterface);

            info.TypeBuilder = typeBuilder;

            foreach (var prop in GetProperties(bakeInterface))
            {
                CreateProperty(
                    info,
                    bakeInterface, bakeImpl,
                    typeBuilder, prop);
            }
            foreach (var method in GetMethods(bakeInterface))
            {
                if (method.IsSpecialName)
                {
                    continue;
                }

                CreateMethod(
                    info,
                    bakeInterface, bakeImpl,
                    typeBuilder, method);
            }

            Type type = typeBuilder.CreateType();

            impl = Activator.CreateInstance(bakeImpl);
            object obj = Activator.CreateInstance(type, new object[] { impl });

            return(obj);
        }
예제 #2
0
        private static MethodBuilder CreateProperty(
            BakeInfo info,
            Type intf, Type impl,
            TypeBuilder typeBuilder, PropertyInfo prop)
        {
            var methodBuilder = typeBuilder.DefineMethod(
                "get_" + prop.Name,
                MethodAttributes.Public |
                MethodAttributes.Virtual |
                MethodAttributes.NewSlot |
                MethodAttributes.HideBySig |
                MethodAttributes.SpecialName |
                MethodAttributes.Final,
                prop.PropertyType,
                null);
            var ilGen = methodBuilder.GetILGenerator();

            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, info.target);
            ilGen.Emit(OpCodes.Callvirt,
                       impl.GetProperty(prop.Name).GetGetMethod(true));
            ilGen.Emit(OpCodes.Ret);

            return(methodBuilder);
        }
예제 #3
0
        private static MethodBuilder CreateMethod(
            BakeInfo info,
            Type intf, Type impl,
            TypeBuilder typeBuilder, MethodInfo method)
        {
            var paramTypes =
                method.GetParameters().Select(m => m.ParameterType).ToArray();
            var methodBuilder = typeBuilder.DefineMethod(
                method.Name,
                MethodAttributes.Public |
                MethodAttributes.Virtual |
                MethodAttributes.NewSlot |
                MethodAttributes.HideBySig |
                MethodAttributes.Final,
                method.ReturnType,
                paramTypes);
            var ilGen = methodBuilder.GetILGenerator();

            /* ld_this */
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, info.target);

            foreach (var param in method.GetParameters())
            {
                ilGen.Emit(OpCodes.Ldarg, param.Position + 1);
            }
            ilGen.Emit(OpCodes.Callvirt,
                       impl.GetMethod(
                           method.Name,
                           method.GetParameters().Select(m => m.ParameterType).ToArray()));
            ilGen.Emit(OpCodes.Ret);

            return(methodBuilder);
        }
예제 #4
0
        public static TBakeInterface Bake <TBakeInterface, TBakeImpl>(TBakeImpl impl)
        {
            var info        = new BakeInfo();
            var typeBuilder = CreateType(info, typeof(TBakeInterface));

            /* black magic */
            foreach (var prop in GetProperties(typeof(TBakeInterface)))
            {
                CreateProperty(
                    info,
                    typeof(TBakeInterface), typeof(TBakeImpl),
                    typeBuilder, prop);
            }
            foreach (var method in GetMethods(typeof(TBakeInterface)))
            {
                Console.WriteLine(method.Name);
                CreateMethod(
                    info,
                    typeof(TBakeInterface), typeof(TBakeImpl),
                    typeBuilder, method);
            }

            Type   type = typeBuilder.CreateType();
            object obj  = Activator.CreateInstance(type);

            type.GetField("target").SetValue(obj, impl);

            return((TBakeInterface)obj);
        }
예제 #5
0
        internal void Bake()
        {
            if (next != null)
            {
                next.Bake();
            }
            if (child != null)
            {
                child.Bake();
            }

            int cc = ChildCount;
            int tc = TotalStateCount;
            int ac = AcceptStateCount;

            bakeinfo = new BakeInfo(cc, tc, ac);
        }
예제 #6
0
        private static TypeBuilder CreateType(
            BakeInfo info,
            Type intf)
        {
            var implName = intf.Name + "Impl";

            var assemblyBuilder =
                AppDomain.CurrentDomain.DefineDynamicAssembly(
                    new AssemblyName(implName),
                    AssemblyBuilderAccess.Run);
            var moduleBuilder =
                assemblyBuilder.DefineDynamicModule("Module");
            var typeBuilder = moduleBuilder.DefineType(
                implName,
                TypeAttributes.Public |
                TypeAttributes.Class |
                TypeAttributes.AutoClass |
                TypeAttributes.AnsiClass |
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.AutoLayout,
                null,
                new Type[] { intf });

            info.Target = typeBuilder.DefineField(
                "target", typeof(object), FieldAttributes.Private);

            ConstructorBuilder ctor =
                typeBuilder.DefineConstructor(
                    MethodAttributes.Public | MethodAttributes.SpecialName,
                    CallingConventions.Standard,
                    new Type[] { typeof(object) });
            ILGenerator ilGen =
                ctor.GetILGenerator();

            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.Emit(OpCodes.Stfld, info.Target);
            ilGen.Emit(OpCodes.Ret);

            return(typeBuilder);
        }
예제 #7
0
        private static MethodBuilder CreateMethod(
            BakeInfo info,
            Type intf, Type impl,
            TypeBuilder typeBuilder, MethodInfo method)
        {
            var paramTypes =
                method.GetParameters().Select(m => m.ParameterType).ToArray();
            var methodBuilder = typeBuilder.DefineMethod(
                method.Name,
                MethodAttributes.Public |
                MethodAttributes.Virtual |
                MethodAttributes.NewSlot |
                MethodAttributes.HideBySig |
                MethodAttributes.Final,
                method.ReturnType,
                paramTypes);
            var ilGen = methodBuilder.GetILGenerator();

            /* args... -> object[] */
            int argc       = 0;
            var args       = ilGen.DeclareLocal(typeof(object[]));
            var typeInfo   = ilGen.DeclareLocal(typeof(Type));
            var methodInfo = ilGen.DeclareLocal(typeof(MethodInfo));

            ilGen.Emit(OpCodes.Ldc_I4, paramTypes.Length);
            ilGen.Emit(OpCodes.Newarr, typeof(object));
            ilGen.Emit(OpCodes.Stloc, args);

            foreach (var param in method.GetParameters())
            {
                ilGen.Emit(OpCodes.Ldloc, args);
                ilGen.Emit(OpCodes.Ldc_I4, argc);
                ilGen.Emit(OpCodes.Ldarg, argc + 1);
                if (paramTypes[argc].IsValueType)
                {
                    ilGen.Emit(OpCodes.Box, paramTypes[argc]);
                }
                ilGen.Emit(OpCodes.Stelem_Ref);

                argc++;
            }

            /* ld_this */
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, info.Target);

            var getTypeFromHandle =
                typeof(Type).GetMethod("GetTypeFromHandle");

            var getMethodFromHandle =
                typeof(MethodBase).GetMethod(
                    "GetMethodFromHandle",
                    new[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) });

            ilGen.Emit(OpCodes.Ldtoken, intf);
            ilGen.Emit(OpCodes.Call, getTypeFromHandle);
            ilGen.Emit(OpCodes.Castclass, typeof(Type));
            ilGen.Emit(OpCodes.Ldtoken, method);
            ilGen.Emit(OpCodes.Ldtoken, method.DeclaringType);
            ilGen.Emit(OpCodes.Call, getMethodFromHandle);
            ilGen.Emit(OpCodes.Castclass, typeof(MethodInfo));

            ilGen.Emit(OpCodes.Ldloc, args);

            /* performs proxy call */
            ilGen.Emit(
                OpCodes.Call,
                impl.GetMethod(
                    "OnMethod",
                    BindingFlags.Instance | BindingFlags.Public));
            if (method.ReturnType != typeof(void))
            {
                if (method.ReturnType.IsValueType)
                {
                    ilGen.Emit(OpCodes.Unbox_Any, method.ReturnType);
                }
                else
                {
                    ilGen.Emit(OpCodes.Castclass, method.ReturnType);
                }
            }
            else
            {
                ilGen.Emit(OpCodes.Pop);
            }

            ilGen.Emit(OpCodes.Ret);

            typeBuilder.DefineMethodOverride(
                methodBuilder,
                method);

            return(methodBuilder);
        }
예제 #8
0
        private static MethodBuilder CreateProperty(
            BakeInfo info,
            Type intf, Type impl,
            TypeBuilder typeBuilder, PropertyInfo prop)
        {
            var name         = prop.Name;
            var type         = prop.PropertyType;
            var backingField = typeBuilder.DefineField(
                "_" + name, type, FieldAttributes.Private);
            var propertyBuilder = typeBuilder.DefineProperty(
                name,
                PropertyAttributes.HasDefault,
                type, new Type[] { type });

            if (prop.CanRead)
            {
                var methodBuilder = typeBuilder.DefineMethod(
                    "get_" + name,
                    MethodAttributes.Public |
                    MethodAttributes.Virtual |
                    MethodAttributes.NewSlot |
                    MethodAttributes.HideBySig |
                    MethodAttributes.SpecialName |
                    MethodAttributes.Final,
                    type,
                    null);
                var ilGen = methodBuilder.GetILGenerator();

                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, info.Target);

                var getTypeFromHandle =
                    typeof(Type).GetMethod("GetTypeFromHandle");
                ilGen.Emit(OpCodes.Ldtoken, type);
                ilGen.Emit(OpCodes.Call, getTypeFromHandle);
                ilGen.Emit(OpCodes.Castclass, typeof(Type));

                ilGen.Emit(OpCodes.Ldstr, name);

                ilGen.Emit(
                    OpCodes.Callvirt,
                    impl.GetMethod(
                        nameof(IFilling.OnGetProperty),
                        BindingFlags.Instance | BindingFlags.Public));
                //ilGen.Emit(OpCodes.Pop);
                if (type.IsValueType)
                {
                    ilGen.Emit(OpCodes.Unbox_Any, type);
                }
                else
                {
                    ilGen.Emit(OpCodes.Castclass, type);
                }
                ilGen.Emit(OpCodes.Ret);

                propertyBuilder.SetGetMethod(methodBuilder);
            }
            if (prop.CanWrite)
            {
                var methodBuilder = typeBuilder.DefineMethod(
                    "set_" + name,
                    MethodAttributes.Public |
                    MethodAttributes.Virtual |
                    MethodAttributes.NewSlot |
                    MethodAttributes.HideBySig |
                    MethodAttributes.SpecialName |
                    MethodAttributes.Final,
                    null,
                    new Type[] { type });
                var ilGen = methodBuilder.GetILGenerator();

                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldfld, info.Target);

                var getTypeFromHandle =
                    typeof(Type).GetMethod("GetTypeFromHandle");
                ilGen.Emit(OpCodes.Ldtoken, type);
                ilGen.Emit(OpCodes.Call, getTypeFromHandle);
                ilGen.Emit(OpCodes.Castclass, typeof(Type));

                ilGen.Emit(OpCodes.Ldstr, name);

                ilGen.Emit(OpCodes.Ldarg_1);
                ilGen.Emit(OpCodes.Box, type);

                ilGen.Emit(
                    OpCodes.Call,
                    impl.GetMethod(
                        nameof(IFilling.OnSetProperty),
                        BindingFlags.Instance | BindingFlags.Public));
                ilGen.Emit(OpCodes.Ret);

                propertyBuilder.SetSetMethod(methodBuilder);
            }

            return(null);
        }