using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MvcCallInterceptors.Controllers;
using System.Reflection;
using System.Linq.Expressions;
namespace MvcCallInterceptors.Interceptors
{
internal sealed class InterceptMethodDispatcher
{
private delegate object InterceptorExecutor(IInterceptorMvcController controller, InterceptorParasDictionary<string,object> parameters, object result);
private delegate void VoidInterceptorExecutor(IInterceptorMvcController controller, InterceptorParasDictionary<string, object> parameters, object result);
private InterceptorExecutor _executor;
public InterceptMethodDispatcher(MethodInfo methodInfo)
{
_executor = GetExecutor(methodInfo);
MethodInfo = methodInfo;
}
public MethodInfo MethodInfo
{
get;
private set;
}
public object Execute(IInterceptorMvcController controller, InterceptorParasDictionary<string, object> parameters, object result)
{
return _executor(controller, parameters, result);
}
private static InterceptorExecutor GetExecutor(MethodInfo methodInfo)
{
// Parameters to executor
ParameterExpression controllerParameter = Expression.Parameter(typeof(IInterceptorMvcController), "controller");
ParameterExpression parametersParameter = Expression.Parameter(typeof(InterceptorParasDictionary<string, object>), "parameters");
ParameterExpression resultParameter = Expression.Parameter(typeof(object), "result");
// Build parameter list
List<Expression> parameters = new List<Expression>();
ParameterInfo[] paramInfos = methodInfo.GetParameters();
ParameterInfo paramInfo0 = paramInfos[0];
UnaryExpression valueCast0 = Expression.Convert(parametersParameter, paramInfo0.ParameterType);
parameters.Add(valueCast0);
ParameterInfo paramInfo1 = paramInfos[1];
UnaryExpression valueCast1 = Expression.Convert(resultParameter, paramInfo1.ParameterType);
parameters.Add(valueCast1);
// 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<VoidInterceptorExecutor> lambda = Expression.Lambda<VoidInterceptorExecutor>(methodCall, controllerParameter, parametersParameter, resultParameter);
VoidInterceptorExecutor voidExecutor = lambda.Compile();
return WrapVoidInterceptorCall(voidExecutor);
}
else
{
// must coerce methodCall to match InterceptorExecutor signature
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<InterceptorExecutor> lambda = Expression.Lambda<InterceptorExecutor>(castMethodCall, controllerParameter, parametersParameter, resultParameter);
return lambda.Compile();
}
}
private static InterceptorExecutor WrapVoidInterceptorCall(VoidInterceptorExecutor executor)
{
return delegate(IInterceptorMvcController controller, InterceptorParasDictionary<string, object> parameters, object result)
{
executor(controller, parameters, result);
return null;
};
}
}
}