How to use partial application like DI? | Greg Young

:

I had an interesting question today on twitter from someone having some issues trying to do what I discuss in my 8 lines of code talk

Unfortunately though while the Event Store does manual wire up it does not also use partial application in that code so its not a great example so I asked for a gist with example code to see what the problem may be.

https://gist.github.com/ndonze/7675989

As you can see the types are the big problem here as it wants a List<Func<IMessage, IHandlerResult>>() unfortunately the compiler will not like this (some languages can actually do this! C# is not one of them). I replied with the following code that works for the particular case

https://gist.github.com/gregoryyoung/7677410

This code is very similar to the first bit (still registers up handlers etc) but it has one small trick being played in it. In particular when registering a handler you will notice:

_dictionary.Add(typeof(T), x => func((T)x));

Internally the Dictionary stores as an internal interface for IMessage. This line of code causes the cast to happen. If I were to write it out as a full function it would look something like:

static MyReturn Convert(IMessage message) {

OtherHandler((ConcreteMessage) message)

}

This allows all the internal things to be treated and dispatched as IMessage but the outside handlers to use a ConcreteMessage. We can go one step further than this though (and probably should). Note that the code is no less testable, we are just passing in dependencies in a different way.

Why should I TELL you what IMessage must be?

https://gist.github.com/gregoryyoung/7677671

This same code can also work for command handlers as well as queries. In order to do this we will take direction from F# (as well as many other languages) and introduce a type that represents void. We need to do this as System.Void is not allowed to be used for generic arguments.

https://gist.github.com/gregoryyoung/7677751

Now we can use this in conjunction with our dispatcher to handle commands as well as an Action<TCommand> is equivalent to a Func<TCommand, Nothing>

https://gist.github.com/gregoryyoung/7677790

Now we can use the same code in either place!