a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
75 lines
3.3 KiB
C#
75 lines
3.3 KiB
C#
namespace System.Web.Mvc {
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
|
|
// The methods in this class don't perform error checking; that is the responsibility of the
|
|
// caller.
|
|
internal sealed class ActionMethodDispatcher {
|
|
|
|
private delegate object ActionExecutor(ControllerBase controller, object[] parameters);
|
|
private delegate void VoidActionExecutor(ControllerBase controller, object[] parameters);
|
|
|
|
private ActionExecutor _executor;
|
|
|
|
public ActionMethodDispatcher(MethodInfo methodInfo) {
|
|
_executor = GetExecutor(methodInfo);
|
|
MethodInfo = methodInfo;
|
|
}
|
|
|
|
public MethodInfo MethodInfo {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public object Execute(ControllerBase controller, object[] parameters) {
|
|
return _executor(controller, parameters);
|
|
}
|
|
|
|
private static ActionExecutor GetExecutor(MethodInfo methodInfo) {
|
|
// Parameters to executor
|
|
ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");
|
|
ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
|
|
|
|
// Build parameter list
|
|
List<Expression> parameters = new List<Expression>();
|
|
ParameterInfo[] paramInfos = methodInfo.GetParameters();
|
|
for (int i = 0; i < paramInfos.Length; i++) {
|
|
ParameterInfo paramInfo = paramInfos[i];
|
|
BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
|
|
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);
|
|
|
|
// valueCast is "(Ti) parameters[i]"
|
|
parameters.Add(valueCast);
|
|
}
|
|
|
|
// Call method
|
|
UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(controllerParameter, methodInfo.ReflectedType) : null;
|
|
MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);
|
|
|
|
// methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"
|
|
// Create function
|
|
if (methodCall.Type == typeof(void)) {
|
|
Expression<VoidActionExecutor> lambda = Expression.Lambda<VoidActionExecutor>(methodCall, controllerParameter, parametersParameter);
|
|
VoidActionExecutor voidExecutor = lambda.Compile();
|
|
return WrapVoidAction(voidExecutor);
|
|
}
|
|
else {
|
|
// must coerce methodCall to match ActionExecutor signature
|
|
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
|
|
Expression<ActionExecutor> lambda = Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter, parametersParameter);
|
|
return lambda.Compile();
|
|
}
|
|
}
|
|
|
|
private static ActionExecutor WrapVoidAction(VoidActionExecutor executor) {
|
|
return delegate(ControllerBase controller, object[] parameters) {
|
|
executor(controller, parameters);
|
|
return null;
|
|
};
|
|
}
|
|
|
|
}
|
|
}
|