0

Can I create an Action delegate with a lambda expression like this () => Method(args) dynamically when I have the target, MethodInfo and arguments to pass in?

Say I had a method that took an int argument and wanted to assign an Action delegate to call it with the argument 1 like so Action action = () => Method(1), but I want to do it dynamically. You could make a delegate and assign the action to dynamically invoke it, or assign it to invoke the method, but the performance is terrible.

public class DelegateData
{
    public object target;
    public MethodInfo method;
    public object[] args;
}
Martin
  • 335
  • 4
  • 13
  • 1
    Possible duplicate of http://stackoverflow.com/questions/12131301/how-can-i-dynamically-create-an-actiont-at-runtime. – Ian H. Jan 01 '17 at 16:27
  • 1
    What are you trying to achieve? It seems rather unclear to me – Samuel Yvon Jan 01 '17 at 16:31
  • @Nobody Create a lambda expression in which a method is called and store it in an Action delegate dynamically. – Martin Jan 01 '17 at 16:48
  • @Nobody The goal is basically to create an Action delegate that calls a method with a bunch of preset arguments. – Martin Jan 01 '17 at 16:49
  • Can't you just call your method and pass the DelegateData as the arguments? https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx – Samuel Yvon Jan 01 '17 at 16:55
  • I've tried to provide an answer to your problem. BTW, I got stuck. While I can generate the whole delegate using expression trees, I can't invoke it. See the code here: https://dotnetfiddle.net/apR5iJ ... Let's see if someone can fix my own code ;P or maybe you can fix it yourself – Matías Fidemraizer Jan 01 '17 at 17:39
  • I can create the delegate with Delegate.CreateDelegate. The problem here is the method can have any number of arguments of all types, so I would need to dynamically construct a delegate type somehow. If I figured that out I'm at a dead end because the only way to dynamically invoke the delegate is DynamicInvoke which has TERRIBLE performance, 4 times as expensive as MethodInfo.Invoke and thousands of times less performant than calling the delegate directly. – Martin Jan 01 '17 at 17:53

1 Answers1

0

Figured it out. It's quite easy with expressions, creating the delegate this way is of course incredibly slow (almost 1 second for 10.000 iterations), but afterward, the delegate is only twice as slow as it would be when created naturally. lambda.Compile is the culprit here, but I see no way around it.

var arguments = args.Select(a => Expression.Constant(a)).ToArray();
var lambda = Expression.Lambda(Expression.Call(Expression.Constant(target), method, arguments));
var result = (Action)lambda.Compile();
Martin
  • 335
  • 4
  • 13