Exemplo n.º 1
0
        public static Delegate CreateMethodCaller(Type delegateType, MethodInfo method)
        {
            // arguments checks
            if (!typeof(Delegate).IsAssignableFrom(delegateType))
            {
                throw new ArgumentException("delegateType does not represents a delegate", nameof(delegateType));
            }

            // 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 method info
            var methodArgs = method.GetParameters().Select(x => x.ParameterType).ToArray();
            var argsCount  = methodArgs.Length;

            //

            Type this_ = method.IsStatic ? null : (method.DeclaringType.IsValueType ? method.DeclaringType.MakeByRefType() : method.DeclaringType);

            var arguments = Enumerable.Empty <Type>();

            if (this_ != null)
            {
                arguments = arguments.Append(this_);
                argsCount++;
            }
            arguments = arguments.Concat(methodArgs);

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

            DynamicMethod wrapper = new DynamicMethod($"method_{method.DeclaringType.Name}_{method.Name}", retType, arguments.ToArray(), typeof(Dynamic), true);
            IILGenerator  gen     = wrapper.GetILGenerator().AsInterface();



            int argIndex = 0;

            if (this_ != null)
            {
                if (this_.IsValueType)
                {
                    // Struct;
                    gen.Ldarga_S((byte)argIndex++);
                }
                else
                {
                    // Class; ref Struct;
                    gen.Ldarg((byte)argIndex++);
                }
            }


            for (int i = 0; i < methodArgs.Length; i++)
            {
                gen.Ldarg((byte)argIndex++);
            }

            gen
            .Call(method)
            .Ret();

            return(wrapper.CreateDelegate(delegateType));
        }