Deferred execution in C# - fun with Funcs

Deferred execution in C# - fun with Funcs

10/16/2014 18:01:21

I want to talk a little about deferred execution in C#.

I use deferred execution a lot in my code – frequently using it to configure libraries and build for extensibility – but I’ve met lots of people that understand the concept of deferred execution (“this happens later”) but have never really brushed up against it in C#.

Deferred execution is where code is declared but not immediately run – instead being invoked later

Deferred execution is formally described by MSDN as meaning “the evaluation of an expression is delayed until its realized value is actually required”.

It’s common in JavaScript to supply a method as a callback which is later invoked:

image

In the above example, we’re declaring a new function while calling doSomething(), that is later executed as a callback by the doSomething() method, rather than being executed when we call it. Because JavaScript is executed linearly, it makes extensive use of callbacks in just about every part of the language.

By contrast, deferred execution is less obvious in C#, even though there have been keywords and types that leverage deferred execution available for years. There are two common ways that deferred execution is implemented in C#

The Yield Keyword

The yield keyword was introduced in C#2 as some sweet syntatic sugar to help people implement iterators and enumerators without boilerplate code. Using the yield keyword generates a state machine at compile time and actually does a surprising amount. There’s a really great (and ancient) post by Raymond Chen about how yield is implemented – but the short version is, you can “yield return” in methods that return an IEnumerable<T> and the compiler will generate a class with a whole bunch of goto statements in it. It’s an elegant compiler trick that a lot of you will have used, even if you didn’t realise it at the time.

The Action and Func Types

Now we get to the fun stuff. Actions and Func’s were also introduced in C#2, but became much more common from C#3 onwards when Lambdas were introduced to the language. They look like this:

image

Delegates and lambdas in C# are collectively called “Anonymous methods”, and (sometimes) act as closures. What this means, is that when an anonymous method is declared, it can capture “outer variables” so that you can use them later.  There’s a good response by Eric Lippert explaining the exact semantics of anonymous methods in a StackOverflow post here, and numerous examples around the web. This is interesting because you can use a closure to capture some context in one place in the application, and invoke it somewhere else.

There are lots of fun use cases for this, and I want to highlight a couple.

Templating methods

Sometimes referred to as the “hole in the middle” pattern – there are plenty of scenarios where you have a block of repetitive identical code, and four or five tiny variations. This is one of the most frequent sources of copy-paste code, and a great refactor for lots of older codebases. You could create an abstract base class, and a whole bunch of inheritance to solve this problem – or you could do something simpler, where this

image 

can trivially become this

image

Entirely removing the repetition from the codebase without having to build a bunch of abstract cruft. The actual bodies of the methods are entirely different, but with some creative use of deferred execution, we can make sure we only include the boilerplate code once. There are more compelling examples though, consider this pattern if you’re boiler plating HTTP requests, or doing repetitive serialization.

Method Interception

If you’re authoring libraries and want to give your users a way to “meddle with the default behaviour” providing them optional func’s is a really neat way to do it without compromising your design. Imagine a library call that by design swallows exceptions – while that’s not a great idea, we’ll run with it. So users might rightfully want to know when this happens, so you can leverage optional parameters and Action callbacks to give them a hook without compromising your library call.

image

This is a very simplistic example – there are whole frameworks built on the concept of wiring up large collections of Funcs and Actions that are chained together. The Nancy web framework’s Before and After hooks are nothing more than a chain of Funcs that get executed in sequence. In fact, the whole of the OWIN work-in-progress spec for the next generation of .NET webservers revolves around the use of a single “AppFunc”.

Mutator Actions and Funcs that leverage current context

I use Funcs for configuration in just about every library that I own. They’re a great way to allow people to configure the future behaviour of a library, in a repeatable way. In the following example I’m going to create a Factory class that will store an Action that it’ll use to modify the type it creates each time create is called.

image

This is especially useful if you want to do something like “get a value out of the current request” or some other thing that changes each time the factory is called – if you design your Actions and Funcs right, passing in the “current executing context” you can declaratively define behaviours at start-up that evaluate differently on each execution.

I’ve commonly used these kinds of configuration overrides to do things like “fetch the current tenant from context” or “get the ISession from a session scoped IoC container” – the configuration model of ReallySimpleEventing is a small example of using deferred execution and Actions to override the default behaviour when the library encounters an unhandled exception. A default “Throw all” implementation is provided, with the ability to override by configuration.

Working around problems with classes you can’t control the creation of

I recently had to dip into doing some WCF code – and one of the less desirable parts about working with WCF is that it creates your services for you. What this means is that if you want to use some kind of DI container across your codebase based around constructor injection, you’re out of luck. It’s annoying, and it can ruin your testing day, but with a little bit of legwork you can use Func’s to plug that hole.

Given a class that looks like this that’s created by some framework magic

image

You can make a publically settable static func, that’ll act as a proxy to your container and bind it up at bootstrapping time. That’s a bit of a mouthful, so let me illustrate it.

image

In the above example, you can wire up a public static Func<MyDependency> to your container in your bootstrapping code. This means that even if you don’t control the lifecycle of your class, you have a hook to callback to the container to grab a current valid instance of your dependency, without relying on deep static class usages or service locators. It’s preferable, because you can override this behaviour in test classes, giving you a way to test this previously hard to test code. This is especially useful if you want to exhume references to HttpContext or some other framework provided static from your code.

Dictionaries of methods for control flow

Here’s a fun example. Lets say you write a command line app, that takes one of five parameters, and you want to execute a different method based on the parameter passed. Simple enough, lets right an if statement!

image

A little naff and repetitive, but it’ll do. You could perhaps refactor this to a switch statement

image

This looks a little tighter, but it’s still quite verbose – even for such a small example. With the help of a dictionary and some Actions, you can convert this to a registry of methods – one that you could even modify at runtime.

image

This is a visibly concise way of expressing the same control flow in a way that’s mutable.

This is just a taste of some of the things you can do when you leverage deferred execution, anonymous methods and the Action and Func types in .NET.  There are plenty of open source codebases that make use of these kinds of patterns in code, so do dig deeper!