如何将具有未知数量参数的方法转换为System.Delegate?
问题描述:
给定一种方法,我需要将其转换为委托,以便我可以在其上调用.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)})")
不够好。
答
研究这个有点后,我发现,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
你试过'params'?你必须创建你自己的代表。我不是100%确定这是否是重复的https://stackoverflow.com/a/1136510/495455,但它非常非常相似。 –
@JeremyThompson不幸的是,这不是我的问题。这并不是说该方法有一个'params'参数,但我不知道它有什么样的参数。 – Pavel
你能提供[mcve]吗?没关系,如果它不起作用... –