Reputation: 100
I am trying to create a Action that uses two parameters, one of the parameters are the class instance and the other is a object array. The object array types are unknown as I find the methods with a attribute, so I gave the below a try but the expr.Compile() throws an error
variable 'arg1[0]' of type 'System.Object' referenced from scope '', but it is not defined
public static T BuildDelegate<T>(MethodInfo method)
{
var dgtMi = typeof(T).GetMethod("Invoke");
var dgtParams = dgtMi.GetParameters();
var preDeterminedParams = new ParameterExpression[2]
{
Expression.Parameter(dgtParams[0].ParameterType, "arg0"),
Expression.Parameter(typeof(object[]), "arg1")
};
var methodParams = method.GetParameters();
var paramThis = Expression.Convert(preDeterminedParams[0], method.DeclaringType);
var paramsToPass = CreateParam(methodParams);
var expr = Expression.Lambda<T>(
Expression.Call(paramThis, method, paramsToPass),
preDeterminedParams);
return expr.Compile();
}
private static Expression[] CreateParam(ParameterInfo[] parameters)
{
var expressions = new Expression[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
//Trying to create a placeholder for any objects that might be passed through arg1
expressions[i] = Expression.Convert(
Expression.Parameter(typeof(object), "arg1[" + i + "]"),
parameters[i].ParameterType);
}
return expressions;
}
expr looks like this before trying to compile
(arg0, arg1) => Convert(arg0, Test).TestingInvocation(Convert(arg1[0], String), Convert(arg1[1], Int32), Convert(arg1[2], Single)
I am guessing since arg1[0] was created in CreateParam() as a place holder it does not have a reference value. Not sure how to create a holder, so it can have some sort of reference.
Essentially I am trying to accomplish this after the expression is compiled
Action<T(anyclass reference), object[] (unknown params)>
(arg0, arg1)=>{ Convert(arg0, T).Method(Convert(arg1[0], ToUnknownType))}
Upvotes: 2
Views: 621
Reputation: 246998
In the following snippet,
//...
//Trying to create a placeholder for any objects that might be passed through arg1
expressions[i] = Expression.Convert(
Expression.Parameter(typeof(object), "arg1[" + i + "]"),
parameters[i].ParameterType);
//...
You are basically doing arg1[0] => ...
which is not a valid expression.
You are most likely looking for Expression.Array*
related calls in order to access the array index.
public static T BuildDelegate<T>(MethodInfo method) {
var dgtMi = typeof(T).GetMethod("Invoke");
var dgtParams = dgtMi.GetParameters();
var preDeterminedParams = new ParameterExpression[2] {
Expression.Parameter(dgtParams[0].ParameterType, "arg0"),
Expression.Parameter(typeof(object[]), "arg1")
};
ParameterInfo[] methodParams = method.GetParameters();
var paramThis = Expression.Convert(preDeterminedParams[0], method.DeclaringType);
// arg1 =>
var arg1 = preDeterminedParams[1];
// arg1 => Convert(arg1[0], SomeType), Convert(arg1[1], SomeType), ....
var paramsToPass = CreateParam(arg1, methodParams);
var expr = Expression.Lambda<T>(
Expression.Call(paramThis, method, paramsToPass),
preDeterminedParams);
return expr.Compile();
}
private static Expression[] CreateParam(ParameterExpression arg1, ParameterInfo[] parameters) {
var expressions = new Expression[parameters.Length];
for (int i = 0; i < parameters.Length; i++) {
//arg1 => Convert(arg1[i], SomeType)
expressions[i] = Expression.Convert(
Expression.ArrayIndex(arg1, Expression.Constant(i)), parameters[i].ParameterType
);
}
return expressions;
}
Upvotes: 4