You cannot do this:
c => c.MyMethod2
Because it is a group of methods. Any method in a method group can return void or something else, so the compiler will not allow this:
Error CS0428 Cannot convert method group '...' to non-delegate type '...'
The group may have a method that returns ActionMethod , or none. You need to solve this.
But you still don't need to provide a group of methods. You can simply use the existing signature minus object routeValues , and name it like this:
Url.Action<MyController>(c => c.MyMethod(99))
Then in your method, you can use MethodInfo methodCallExpression.Method to get the names of the method parameters and methodCallExpression.Arguments to get the arguments.
Then your next problem is creating an anonymous object at runtime. Fortunately, you do not need to, because Url.Action() also has an overload that accepts a RouteValueDictionary .
Replace the parameters and arguments together in the dictionary, create a RouteValueDictionary from it RouteValueDictionary and go to Url.Action() :
var methodCallExpression = expression.Body as MethodCallExpression; if (methodCallExpression == null) { throw new ArgumentException("Not a MethodCallExpression", "expression"); } var methodParameters = methodCallExpression.Method.GetParameters(); var routeValueArguments = methodCallExpression.Arguments.Select(EvaluateExpression); var rawRouteValueDictionary = methodParameters.Select(m => m.Name) .Zip(routeValueArguments, (parameter, argument) => new { parameter, argument }) .ToDictionary(kvp => kvp.parameter, kvp => kvp.argument); var routeValueDictionary = new RouteValueDictionary(rawRouteValueDictionary);
The EvaluateExpression method compiles and calls every mutable expression very naively, so in practice it may seem pretty slow:
private static object EvaluateExpression(Expression expression) { var constExpr = expression as ConstantExpression; if (constExpr != null) { return constExpr.Value; } var lambda = Expression.Lambda(expression); var compiled = lambda.Compile(); return compiled.DynamicInvoke(); }
However, the Microsoft ASP.NET MVC Futures package has a convenient ExpressionHelper.GetRouteValuesFromExpression(expr)ββ which also handles routing and areas. Then your whole method can be replaced by:
var routeValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression<T>(expression); return url.Action(routeValues["Action"], routeValues["Controller"], routeValues);
It uses a built-in expression compiler in the cache, so it works for all uses, and you donβt have to reinvent the wheel.