Is it possible to obtain ParameterInfo
and argument values for a delegate invocation which is inside a (compiler-generated) LambdaExpression
?
For example I have defined a delegate:
public class A
{
public delegate string[] GetInfo(int[] ids);
}
Now I need to use an expression to obtain the parameter values with the PropertyInfo
of the delegate parameters. Only way I was able to get the Expression
to work is to use it as an Action
:
public readonly struct DelegateInfo
{
public Type ReturnType{ get; }
public Dictionary<ParameterInfo, object> Parameters { get; }
}
public class B
{
public B()
{
var info = GetDelegateInfo<A.GetInfo>(del => del(new int[]{1,2,3}));
}
public DelegateInfo GetDelegateInfo<TDelegate>(Expression<Action<TDelegate>> exp)
where TDelegate : Delegate
{
// Get the action of the expression
var action = exp.Parameters[0];
// How to obtain the delegate ParameterInfo and values?
...
return new DelegateInfo { ... };
}
}
Is this the right way to achieve this? Is there a better way?
With updated struct to:
public readonly struct DelegateInfo
{
public Type ReturnType { get; init; }
public Dictionary<ParameterInfo, object> Parameters { get; init; }
}
The main trick is to get the Invoke
method of the delegate and do something like:
DelegateInfo GetDelegateInfo<TDelegate>(Expression<Action<TDelegate>> exp)
where TDelegate : Delegate
{
var type = typeof(TDelegate); // or exp.Parameters[0].Type
var methodInfo = type.GetMethod("Invoke"); // get the invoke method
// TODO: throw error if not an InvocationExpression
var invocationExpression = exp.Body as InvocationExpression;
return new DelegateInfo
{
ReturnType = methodInfo.ReturnType,
Parameters = methodInfo.GetParameters()
.Zip(invocationExpression.Arguments) // get passed arguments
.ToDictionary(t => t.Item1, t =>
{
var argument = t.Item2;
// quick and dirty approach - compile and invoke
// possibly better to visit the expression
// but will require much more work
return Expression.Lambda<Func<object>>(argument).Compile()();
})
};
}