1 namespace System.Web.Mvc {
3 using System.Collections.Generic;
4 using System.Linq.Expressions;
5 using System.Reflection;
7 // The methods in this class don't perform error checking; that is the responsibility of the
9 internal sealed class ActionMethodDispatcher {
11 private delegate object ActionExecutor(ControllerBase controller, object[] parameters);
12 private delegate void VoidActionExecutor(ControllerBase controller, object[] parameters);
14 private ActionExecutor _executor;
16 public ActionMethodDispatcher(MethodInfo methodInfo) {
17 _executor = GetExecutor(methodInfo);
18 MethodInfo = methodInfo;
21 public MethodInfo MethodInfo {
26 public object Execute(ControllerBase controller, object[] parameters) {
27 return _executor(controller, parameters);
30 private static ActionExecutor GetExecutor(MethodInfo methodInfo) {
31 // Parameters to executor
32 ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");
33 ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");
35 // Build parameter list
36 List<Expression> parameters = new List<Expression>();
37 ParameterInfo[] paramInfos = methodInfo.GetParameters();
38 for (int i = 0; i < paramInfos.Length; i++) {
39 ParameterInfo paramInfo = paramInfos[i];
40 BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));
41 UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);
43 // valueCast is "(Ti) parameters[i]"
44 parameters.Add(valueCast);
48 UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(controllerParameter, methodInfo.ReflectedType) : null;
49 MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);
51 // methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"
53 if (methodCall.Type == typeof(void)) {
54 Expression<VoidActionExecutor> lambda = Expression.Lambda<VoidActionExecutor>(methodCall, controllerParameter, parametersParameter);
55 VoidActionExecutor voidExecutor = lambda.Compile();
56 return WrapVoidAction(voidExecutor);
59 // must coerce methodCall to match ActionExecutor signature
60 UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
61 Expression<ActionExecutor> lambda = Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter, parametersParameter);
62 return lambda.Compile();
66 private static ActionExecutor WrapVoidAction(VoidActionExecutor executor) {
67 return delegate(ControllerBase controller, object[] parameters) {
68 executor(controller, parameters);