Ejemplo n.º 1
0
        public static Delegate ConstructorCaller(Type delegateType, ConstructorInfo constructor, Type instanceType)
        {
            // arguments checks
            if (!typeof(Delegate).IsAssignableFrom(delegateType))
            {
                throw new ArgumentException("delegateType does not represents a delegate", nameof(delegateType));
            }

            if (instanceType == null && !instanceType.IsValueType)
            {
                throw new ArgumentNullException(nameof(instanceType));
            }

            if (constructor == null && !instanceType.IsValueType)
            {
                throw new ArgumentException("constructor is null, but instanceType is not a value type", nameof(instanceType));
            }

            // read delegate info
            var methodInfo   = delegateType.GetMethod("Invoke");
            var delegateArgs = methodInfo.GetParameters().Select(x => x.ParameterType).ToArray() ?? Type.EmptyTypes;
            var retType      = methodInfo.ReturnType != typeof(void) ? methodInfo.ReturnType : null;

            // read constructor info
            var ctorArgs = constructor?.GetParameters().Select(x => x.ParameterType).ToArray() ?? Type.EmptyTypes;

            if (delegateArgs.Length != ctorArgs.Length)
            {
                throw new Exception("deletage's arguments count does not match constructor's arguments count");
            }

            //

            var targetType = constructor?.DeclaringType ?? instanceType;


            DynamicMethod wrapper = new DynamicMethod($"ctor_{targetType.Name}_", retType, delegateArgs, typeof(Dynamic), true);
            IILGenerator  gen     = wrapper.GetILGenerator().AsInterface();

            if (targetType.IsValueType && ctorArgs.Length == 0)
            {
                CreateInitValueType(targetType, gen);
            }
            else
            {
                List <ILArgBuilder> argBuilders = new List <ILArgBuilder>();

                for (int i = 0; i < ctorArgs.Length; i++)
                {
                    argBuilders.Add(ILMethodBuilder.GetArgBuilder(gen, delegateArgs[i], ctorArgs[i]));
                }

                for (int i = 0; i < ctorArgs.Length; i++)
                {
                    argBuilders[i].Prepare((byte)i);
                }

                for (int i = 0; i < ctorArgs.Length; i++)
                {
                    argBuilders[i].PassArg((byte)i);
                }

                gen.Newobj(constructor);

                for (int i = ctorArgs.Length - 1; i >= 0; i--)
                {
                    argBuilders[i].Finalize_((byte)i);
                }
            }
            gen.Ret();
            return(wrapper.CreateDelegate(delegateType));
        }