How to create a delegate from a MethodInfo when method signature cannot be known beforehand?

后端 未结 2 2059
囚心锁ツ
囚心锁ツ 2020-12-07 16:31

I need a method that takes a MethodInfo instance representing a non-generic static method with arbitrary signature and returns a delegate bound to that method t

相关标签:
2条回答
  • 2020-12-07 17:13

    You may want to try System.LinQ.Expressions

    ...
    using System.Linq.Expressions;
    ...
    
    static Delegate CreateMethod(MethodInfo method)
    {
        if (method == null)
        {
            throw new ArgumentNullException("method");
        }
    
        if (!method.IsStatic)
        {
            throw new ArgumentException("The provided method must be static.", "method");
        }
    
        if (method.IsGenericMethod)
        {
            throw new ArgumentException("The provided method must not be generic.", "method");
        }
    
        var parameters = method.GetParameters()
                               .Select(p => Expression.Parameter(p.ParameterType, p.Name))
                               .ToArray();
        var call = Expression.Call(null, method, parameters);
        return Expression.Lambda(call, parameters).Compile();
    }
    

    and use it later as following

    var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
    method.DynamicInvoke("Test Test");
    
    0 讨论(0)
  • 2020-12-07 17:32

    You can use System.Linq.Expressions.Expression.GetDelegateType method:

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;
    
    class Program
    {
        static void Main()
        {
            var writeLine = CreateDelegate(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
            writeLine.DynamicInvoke("Hello world");
    
            var readLine = CreateDelegate(typeof(Console).GetMethod("ReadLine", Type.EmptyTypes));
            writeLine.DynamicInvoke(readLine.DynamicInvoke());
        }
    
        static Delegate CreateDelegate(MethodInfo method)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }
    
            if (!method.IsStatic)
            {
                throw new ArgumentException("The provided method must be static.", "method");
            }
    
            if (method.IsGenericMethod)
            {
                throw new ArgumentException("The provided method must not be generic.", "method");
            }
    
            return method.CreateDelegate(Expression.GetDelegateType(
                (from parameter in method.GetParameters() select parameter.ParameterType)
                .Concat(new[] { method.ReturnType })
                .ToArray()));
        }
    }
    

    There is probably a copy-paste error in the 2nd check for !method.IsStatic - you shouldn't use ArgumentNullException there. And it is a good style to provide a parameter name as an argument to ArgumentException.

    Use method.IsGenericMethod if you want to reject all generic methods and method.ContainsGenericParameters if you want to reject only generic methods having unsubstituted type parameters.

    0 讨论(0)
提交回复
热议问题