Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当方法签名事先未知时,如何从MethodInfo创建委托?_C#_.net_Reflection_Delegates_Methodinfo - Fatal编程技术网

C# 当方法签名事先未知时,如何从MethodInfo创建委托?

C# 当方法签名事先未知时,如何从MethodInfo创建委托?,c#,.net,reflection,delegates,methodinfo,C#,.net,Reflection,Delegates,Methodinfo,我需要一个方法,它接受一个表示具有任意签名的非泛型静态方法的MethodInfo实例,并返回绑定到该方法的委托,该委托稍后可以使用delegate.DynamicInvoke方法调用。我第一次天真的尝试是这样的: using System; using System.Reflection; class Program { static void Main() { var method = CreateDelegate(typeof (Console).GetMe

我需要一个方法,它接受一个表示具有任意签名的非泛型静态方法的
MethodInfo
实例,并返回绑定到该方法的委托,该委托稍后可以使用
delegate.DynamicInvoke
方法调用。我第一次天真的尝试是这样的:

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        var method = CreateDelegate(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
        method.DynamicInvoke("Hello world");
    }

    static Delegate CreateDelegate(MethodInfo method)
    {
        if (method == null)
        {
            throw new ArgumentNullException("method");
        }

        if (!method.IsStatic)
        {
            throw new ArgumentNullException("method", "The provided method is not static.");
        }

        if (method.ContainsGenericParameters)
        {
            throw new ArgumentException("The provided method contains unassigned generic type parameters.");
        }

        return method.CreateDelegate(typeof(Delegate)); // This does not work: System.ArgumentException: Type must derive from Delegate.
    }
}
我希望
MethodInfo.CreateDelegate
方法本身能够找出正确的委托类型。嗯,显然不能。那么,如何创建
系统的实例。键入
,表示具有与提供的
MethodInfo
实例匹配的签名的委托?

您可以使用以下方法:

第二次检查
时可能出现复制粘贴错误!方法.IsStatic
-您不应该在那里使用
ArgumentNullException
。提供参数名作为
ArgumentException
的参数是一种很好的方式


如果要拒绝所有泛型方法,请使用
method.IsGenericMethod
;如果要仅拒绝具有未替换类型参数的泛型方法,请使用
method.ContainsGenericParameters

您可以尝试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();
}
并在以后使用它,如下所示

var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");

此解决方案带来了巨大的开销:它构建表达式树、运行表达式树编译器、生成动态方法并创建该方法的委托。然后,对委托的所有后续调用都通过这个不必要的代理动态方法进行。创建一个直接绑定到提供的
MethodInfo
实例的委托要好得多。@OksanaGimmel整个过程仅用于获取委托。拥有委托引用后,只需调用它即可。@nwafal,虽然这是每个CLR主机或AppDomain化身的最佳一次性初始化,但这并不影响Oksana的评论,因为询问者没有指出委托随后将被调用多少次,与给定会话所需的这种类型的不同委托的数量相比。请注意,即使是在单次初始化/多次使用的最佳情况下,如果这是应用程序中唯一使用
Linq.Expressions
,您在解决和加载多余库方面也会遇到重大困难,而且可能是在最坏的情况下,在启动期间。为什么要创建委托并使用DynamicInvoke?使用DynamicInvoke比MethodInfo.Invoke慢得多。@nawfal-Nope。副本要求此处提出的问题可以在您提到的问题中得到回答。当表示方法签名的类型未知时,询问者希望能够使用
MethodInfo.CreateDelegate()
。在另一个问题中,这已经被称为
MyDelegate
,因此对提问者的问题没有帮助。到底是谁在删除我的评论?不是第一次!抱歉@einsteinsci我找不到我在这里发布的重复线程,所以我无法检查。如果你能发布,我将不胜感激。好的,从谷歌缓存中找到它:。你说得对,他们不一样。标题把我弄糊涂了。很好的解决方案,但是对于没有参数的方法,创建的委托类型不反映out修饰符。@MaMazav你知道如何让它对没有参数的方法起作用吗?感谢you@fobisthename我没有找到一个普遍的解决办法。在我的特定场景中,我可以手动处理使用委托的代码中out/ref参数的情况。因此,我可以通过将原始MethodInfo对象传递给使用委托的代码来解决问题t,并手动询问任何参数(如果它是out参数(ParameterInfo有IsOut和IsByRef属性)。@MaMazav您知道有没有一种方法可以在创建委托后,在不使用动态调用的情况下调用它?我感兴趣的是重构我的代码,停止使用反射(MethofInfo.Invoke)调用方法,转而开始使用委托。但我注意到动态调用比调用更慢。我的问题是我要调用的方法何时具有输出参数。我将发布一个关于这个的问题。为了给未来的读者提供完整性:我想你是在谈论-正如你所回答的,这里的问题比我们这里讨论的要简单得多,正如你所知道的编译时的方法签名。在这里,我们讨论的是这样一种情况,在这种情况下,您没有关于编译时的这些信息,因此需要使用所有这些技巧。对于这种情况,我找到的唯一解决方案是在运行时使用表达式构建匹配的拦截器方法,并在运行时编译此方法。
var method = CreateMethod(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
method.DynamicInvoke("Test Test");