DeftTech.DuckTyping.DelegateDuckProxyType.GenerateProxyType C# (CSharp) Method

GenerateProxyType() private method

If a proxy type has not been generated yet, generates a proxy type that defines a method matching the method signature of the to delegate type given in the constructor which forwards calls to a delegate of the from type given in the constructor.
private GenerateProxyType ( ) : void
return void
        private void GenerateProxyType()
        {
            if (m_ProxyType == null)
            {
                if (!CanProxy())
                {
                    throw new ArgumentException(m_FromDelegateType.FullName + " is not compatible with " + m_ToDelegateType.FullName + ".");
                }

                AssemblyBuilderAccess assemblyBuilderAccess;

            //#if !DEBUG
                assemblyBuilderAccess = AssemblyBuilderAccess.Run;
            //#else
                //assemblyBuilderAccess = AssemblyBuilderAccess.RunAndSave;
            //#endif

                AppDomain domain = Thread.GetDomain();
                string assemblyName = "DuckDelegateProxy_" + m_ToDelegateType.Name.Replace(".", "_").Replace("+", "-") + "_" + m_FromDelegateType.Name.Replace(".", "_").Replace("+", "-") + ".dll";
                AssemblyBuilder assembly = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), assemblyBuilderAccess);
                ModuleBuilder module = assembly.DefineDynamicModule(assemblyName);

                TypeBuilder proxyType = module.DefineType("DuckDelegateProxy");
                proxyType.AddInterfaceImplementation(typeof(IDuckProxy));

                // Define private field to hold a reference to the duck delegate to forward calls to.
                FieldBuilder duckDelegateField = proxyType.DefineField("m_DuckDelegate", m_FromDelegateType, FieldAttributes.Private);

                // Define private .ctor(duckDelegateType duckDelegate)
                ConstructorBuilder constructor = proxyType.DefineConstructor(MethodAttributes.Private, CallingConventions.HasThis, new Type[] { m_FromDelegateType });
                ILGenerator constructorIL = constructor.GetILGenerator();
                constructorIL.Emit(OpCodes.Ldarg_0);
                constructorIL.Emit(OpCodes.Ldarg_1);
                constructorIL.Emit(OpCodes.Stfld, duckDelegateField);
                constructorIL.Emit(OpCodes.Ret);

                // Define Invoke method
                MethodBuilder invokeMethod = ImplementInvokeMethod(proxyType, duckDelegateField);

                // Define public static Delegate Wrap(Delegate duck)
                MethodBuilder wrapMethod = proxyType.DefineMethod("Wrap", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(Delegate), new Type[] { typeof(Delegate) });
                ILGenerator wrapMethodIL = wrapMethod.GetILGenerator();
                wrapMethodIL.Emit(OpCodes.Ldarg_0);
                wrapMethodIL.Emit(OpCodes.Newobj, constructor);
                wrapMethodIL.Emit(OpCodes.Ldftn, invokeMethod);
                wrapMethodIL.Emit(OpCodes.Newobj, m_ToDelegateType.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                wrapMethodIL.Emit(OpCodes.Ret);

                // Define public object UnwrapDuck() - Implementation of IDuckProxy
                MethodBuilder unwrapMethod = proxyType.DefineMethod("UnwrapDuck", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, CallingConventions.HasThis, typeof(object), new Type[0]);
                ILGenerator unwrapMethodIL = unwrapMethod.GetILGenerator();
                unwrapMethodIL.Emit(OpCodes.Ldarg_0);
                unwrapMethodIL.Emit(OpCodes.Ldfld, duckDelegateField);
                unwrapMethodIL.Emit(OpCodes.Ret);

                // Bake it
                m_ProxyType = proxyType.CreateType();
                m_WrapDuck = (WrapDuckDelegate)(Delegate.CreateDelegate(typeof(WrapDuckDelegate), m_ProxyType, wrapMethod.Name));
                m_InvokeMethod = m_ProxyType.GetMethod("Invoke");

            //#if DEBUG
                // If we're in debug mode, save the assembly so we can disassemble it if we want.
                //assembly.Save(assemblyName);
            //#endif
            }
        }