2017-10-17 73 views
1

给定一种方法,我需要将其转换为委托,以便我可以在其上调用.DynamicInvoke()。因此,举例来说,给定方法Foo,我不能做new Action<dynamic, dynamic>(Foo),因为我实际上并不知道Foo必须有2个参数。如何将具有未知数量参数的方法转换为System.Delegate?

那么如何在不知道参数的情况下将方法转换为Delegate

此问题与代码生成有关。我想写生成C#代码的方法,把它归结为:

void GenerateCall(string method, params string[] args) { 
    Console.WriteLine($"Delegate del_{method} = {/*Convert method to delegate here*/};"); 
    Console.WriteLine($"del_{method}.DynamicInvoke({string.Join(", ", args)});"); 
} 

分配的方法给一个变量是我在做什么重要,Console.WriteLine($"{method}({string.Join(", ", args)})")不够好。

+0

你试过'params'?你必须创建你自己的代表。我不是100%确定这是否是重复的https://stackoverflow.com/a/1136510/495455,但它非常非常相似。 –

+0

@JeremyThompson不幸的是,这不是我的问题。这并不是说该方法有一个'params'参数,但我不知道它有什么样的参数。 – Pavel

+0

你能提供[mcve]吗?没关系,如果它不起作用... –

回答

1

研究这个有点后,我发现,Expression类有会自动选择合适的Func<...>Action<...>委托类型为你,甚至在运行时创建新的自定义委托类型的方法,如果没有匹配(即你具有比内置委托类型中可用参数更多的参数)。

用这种方法,你的问题的其余部分对我来说似乎相对简单。下面是如何使用Expression.GetDelegateType()才能获得相应的委托类型,并从随后可用于调用使用所提供的参数的方法,适当的委托实例创建一个例子:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Program program = new Program(); 

     InvokeMethod(null, typeof(Program), "M1", "foo"); 
     InvokeMethod(null, typeof(Program), "M2", 17, "bar"); 
     InvokeMethod(program, typeof(Program), "M3", false); 
    } 

    static void M1(string text) 
    { 
     WriteLine($"M1: {text}"); 
    } 

    static void M2(int i, string text) 
    { 
     WriteLine($"M2: {i}, {text}"); 
    } 

    void M3(bool f) 
    { 
     WriteLine($"M3: {f}"); 
    } 

    static void InvokeMethod(object instance, Type type, string methodName, params object[] args) 
    { 
     Delegate d = CreateDelegate(instance, type, methodName); 

     d.DynamicInvoke(args); 
    } 

    static Delegate CreateDelegate(object instance, Type type, string methodName) 
    { 
     MethodInfo mi = type.GetMethod(methodName, 
      BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance); 
     Type delegateType = Expression.GetDelegateType(mi.GetParameters() 
      .Select(pi => pi.ParameterType) 
      .Concat(new[] { mi.ReturnType }).ToArray()); 

     return Delegate.CreateDelegate(delegateType, instance, mi); 
    } 
} 
+0

非常感谢你!这正是我需要的。 – Pavel

相关问题