private static void CreateMethod(AmObjectClassBuildingContext context, IAmBindingDescription bindingDesc, MethodInfo method)
        {
            var methodBuilder = context.TypeBuilder.DefineMethod(method.Name,
                                                                 MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig |
                                                                 MethodAttributes.NewSlot | MethodAttributes.Virtual);

            methodBuilder.SetParameters(method.GetParameters().Select(x => x.ParameterType).ToArray());
            methodBuilder.SetReturnType(method.ReturnType);
            methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);
            var il    = new CilEmitterSugar(methodBuilder.GetILGenerator());
            var field = context.Fields.GetOrAddBindingField(bindingDesc);

            if (method.Name.StartsWith("get_"))
            {
                il.Ldarg(0);
                il.Ldfld(field);
                il.Call(bindingDesc.MakePropertyGetMethod(context.AmClass));
                il.Ret();
            }
            else if (method.Name.StartsWith("set_"))
            {
                il.Ldarg(0);
                il.Ldfld(field);
                il.Ldarg(1);
                il.Call(bindingDesc.MakePropertySetMethod(context.AmClass));
                il.Ret();
            }
            else
            {
                throw new Exception($"Either getter or setter expected, but '{method.Name}' found.");
            }
            context.TypeBuilder.DefineMethodOverride(methodBuilder, method);
        }
        private void CreateInitBindingsMethod(AmObjectClassBuildingContext context)
        {
            var methodBuilder = context.TypeBuilder.DefineMethod("AmInitBindings", MethodAttributes.Public | MethodAttributes.Virtual);

            methodBuilder.SetParameters(Type.EmptyTypes);
            methodBuilder.SetReturnType(typeof(List <IAmBinding>));
            methodBuilder.SetImplementationFlags(MethodImplAttributes.Managed);
            var il      = new CilEmitterSugar(methodBuilder.GetILGenerator());
            var varList = il.DeclareLocal(typeof(List <IAmBinding>));

            il.Newobj(typeof(List <IAmBinding>).GetConstructor(Type.EmptyTypes));
            il.Stloc(varList);
            foreach (var bindingDesc in context.Desc.Bindings)
            {
                var field = context.Fields.GetOrAddBindingField(bindingDesc);
                il.Ldarg(0);                         // [this]
                il.Dup();                            // [this, this]
                il.Ldstr(bindingDesc.Property.Name); // [this, this, propName]
                il.Ldc_I4((int)bindingDesc.Flags);   // [this, this, propName, flags]
                var bindingCtor = field.FieldType.GetConstructors().Single();
                il.Newobj(bindingCtor);              // [this, binding]
                il.Stfld(field);                     // []
                il.Ldloc(varList);                   // [list]
                il.Ldarg(0);                         // [list, this]
                il.Ldfld(field);                     // [list, binding]
                var addMethod = typeof(List <IAmBinding>).GetMethod(nameof(List <IAmBinding> .Add));
                il.Callvirt(addMethod);              // []
            }
            il.Ldloc(varList);
            il.Ret();
        }
 private static void CreateBindingMethods(AmObjectClassBuildingContext context, IAmBindingDescription bindingDesc)
 {
     CreateMethod(context, bindingDesc, bindingDesc.Property.GetMethod);
     if (bindingDesc.Property.SetMethod != null)
     {
         CreateMethod(context, bindingDesc, bindingDesc.Property.SetMethod);
     }
 }
        public IAmObjectInstantiator CreateObjectClass(Type objectInterface, Func <Type, object> getDefaultDependency)
        {
            var typeBuilder = DeclareType(objectInterface);
            var context     = new AmObjectClassBuildingContext(objectInterface, typeBuilder, bindingTypeDescriptors);

            CreateConstructor(context);
            foreach (var bindingDesc in context.Desc.Bindings)
            {
                CreateBindingMethods(context, bindingDesc);
            }
            CreateInitBindingsMethod(context);
            var objectClass      = typeBuilder.CreateType();
            var instantiatorType = typeof(AmObjectInstantiator <>).MakeGenericType(objectClass);

            return((IAmObjectInstantiator)instantiatorType.GetConstructors().Single().Invoke(new object[] { getDefaultDependency }));
        }
        private void CreateConstructor(AmObjectClassBuildingContext context)
        {
            var baseConstructor    = context.AmClass.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance).Single();
            var parameterTypes     = baseConstructor.GetParameters().Select(x => x.ParameterType).ToArray();
            var constructorBuilder = context.TypeBuilder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.Standard, parameterTypes);

            var il = new CilEmitterSugar(constructorBuilder.GetILGenerator());

            il.Ldarg(0);                // [this]
            for (int i = 0; i < parameterTypes.Length; i++)
            {
                il.Ldarg(i + 1);
            }
            il.Call(baseConstructor);   // []

            //il.Ldarg(0);
            //il.Callvirt(typeof(IAmObject).GetMethod(nameof(IAmObject.AmOnFinalized)));

            il.Ret();
        }