public static MethodBuilder CreateDelegateImplementation(TypeBuilder typeBuilder, FieldBuilder targetField, MethodInfo mi)
        {
            MethodBuilder methodBuilder = typeBuilder.DefineMethod(mi.Name,
                                                                   MethodAttributes.Public | MethodAttributes.Virtual,
                                                                   mi.ReturnType,
                                                                   mi.GetParameters().Select(param => param.ParameterType).ToArray());

            ILGenerator il = methodBuilder.GetILGenerator();

            #region forwarding implementation

            LocalBuilder baseReturn = null;

            if (mi.ReturnType != typeof(void))
            {
                baseReturn = il.DeclareLocal(mi.ReturnType);
            }

            // Call the target method
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, targetField);

            // Load the call parameters
            for (int i = 0; i < mi.GetParameters().Length; i++)
            {
                CodeGenUtil.EmitLoadArgument(il, i);
            }

            // Make the call
            MethodInfo callTarget = targetField.FieldType.GetMethod(mi.Name, mi.GetParameters().Select(pi => pi.ParameterType).ToArray());
            il.Emit(OpCodes.Callvirt, callTarget);

            if (mi.ReturnType != typeof(void))
            {
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldloc_0);
            }

            il.Emit(OpCodes.Ret);

            #endregion

            return(methodBuilder);
        }
 static DuckTypingProxyFactory()
 {
     _assemblyBuilder = CodeGenUtil.CreateAssemblyBuilder(_assemblyName);
     _moduleBuilder   = CodeGenUtil.CreateModuleBuilder(_assemblyBuilder, _assemblyName);
 }
        public Type GenerateProxyType(Type typeOfIMyDuck, Type typeOfOtherDuck)
        {
            TypeAttributes newAttributes = TypeAttributes.Public | TypeAttributes.Class;
            TypeBuilder    typeBuilder   = _moduleBuilder.DefineType(
                typeOfOtherDuck.Name + "_DuckTypingProxy" + Guid.NewGuid().ToString(), newAttributes);

            // Add interface implementation
            typeBuilder.AddInterfaceImplementation(typeOfIMyDuck);

            FieldBuilder targetField = typeBuilder.DefineField("target", typeOfOtherDuck, FieldAttributes.Private);

            foreach (MethodInfo mi in typeOfIMyDuck.GetMethods())
            {
                CodeGenUtil.CreateDelegateImplementation(typeBuilder, targetField, mi);
            }

            foreach (PropertyInfo pi in typeOfIMyDuck.GetProperties())
            {
                PropertyBuilder pb = typeBuilder.DefineProperty(
                    pi.Name,
                    pi.Attributes,
                    pi.PropertyType,
                    pi.GetIndexParameters().Select(param => param.ParameterType).ToArray()
                    );
                MethodInfo getMi = pi.GetGetMethod();
                if (getMi != null)
                {
                    MethodBuilder getMethod = CodeGenUtil.CreateDelegateImplementation(typeBuilder, targetField, getMi);
                    pb.SetGetMethod(getMethod);
                }

                MethodInfo setMi = pi.GetSetMethod();
                if (setMi != null)
                {
                    MethodBuilder setMethod = CodeGenUtil.CreateDelegateImplementation(typeBuilder, targetField, setMi);
                    pb.SetSetMethod(setMethod);
                }
            }

            //Constructor
            ConstructorBuilder ctorBuilder = typeBuilder.DefineConstructor(
                MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                CallingConventions.HasThis,
                new Type[] { typeOfOtherDuck });

            ctorBuilder.DefineParameter(1, ParameterAttributes.None, "target");
            ILGenerator il = ctorBuilder.GetILGenerator();

            // Call base class constructor
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, CodeGenUtil.GetConstructorInfo(() => new object()));

            // Initialize the target field
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Stfld, targetField);
            il.Emit(OpCodes.Ret);

            Type result = typeBuilder.CreateType();

#if DEBUG
            _assemblyBuilder.Save(_assemblyName + ".dll");
#endif
            return(result);
        }