How Are Anonymous Delegates Working in ControllerActionInvoker.InvokeActionMethodWithFilters

162 views Asked by At

I'm trying to make the move from PHP to ASP.NET and in doing so I'm trying to learn how the MVC works, however I'm stuck with the ControllerActionInvoker.InvokeActionMethodWithFilters as I don't understand what is happening.

The snippet I'm struggling with is the following:

protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IList<IActionFilter> filters, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
    ActionExecutingContext preContext = new ActionExecutingContext(controllerContext, actionDescriptor, parameters);
    Func<ActionExecutedContext> continuation = () =>
                                               new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
                                               {
                                                   Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
                                               };

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
                                                                    (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));
    return thunk();
}

The full source code can be found at the following URL: https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ControllerActionInvoker.cs#L371

In particular, I'm unsure on what the following is doing:

    Func<ActionExecutedContext> continuation = () =>
                                               new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
                                               {
                                                   Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
                                               };

As I've never seen a line containing the following before: continuation = () =>

Nor can I seem to find an answer on Google because it doesn't recognise = () => as a search term.

I'm just as confused with the following snippet of code which has a similar syntax:

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
                                                                    (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));

Coming from a PHP background, I've not seen this syntax before, and the resources I've read online don't really clear things up for me either.

On the basis of the following SO question: delegate keyword vs. lambda notation

If I was to rewrite the following...

    Func<ActionExecutedContext> continuation = () =>
                                               new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */)
                                               {
                                                   Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
                                               };

Would it look like so...

    Func<ActionExecutedContext> continuation = delegate(new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */))
                                               {
                                                   Result = InvokeActionMethod(controllerContext, actionDescriptor, parameters)
                                               };

And same for the second snippet...

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
                                                                    (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));

Which if I'm not mistaken would be...

    // need to reverse the filter list because the continuations are built up backward
    Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation, delegate(next, filter) {InvokeActionMethodFilter(filter, preContext, next)});

Or am I still not getting it?

1

There are 1 answers

2
lorond On BEST ANSWER

It's a lambda expressions, and in this particular case it is nothing more then anonymous functions.

Which if I'm not mistaken would be...

Wrong. It is delegate to function with two parameters next and filter, that returns delegate to another function, that calls InvokeActionMethodFilter method:

Func<ActionExecutedContext> thunk =
    filters.Reverse()
           .Aggregate(continuation,
                      delegate(Func<ActionExecutedContext> next, IActionFilter filter)
                      {
                          return delegate
                          {
                              return InvokeActionMethodFilter(filter, preContext, next);
                          };
                      });

This code chains IActionFilters invocation until some of them produce result. And at the end of chain is your action method. Variable next is either filter executing function () => InvokeActionMethodFilter(filter, preContext, next), or continuation at the end of chain. See InvokeActionMethodFilter implementation for details.