When you’re working with C# and reflection, you might end up in a situation where you have “lost” the type. For example, if you’ve deserialized an incoming message of some kind, you might have code that needs to do this:
|
void HandleTheMessage(object message) { // ... nasty reflection code in here } |
Usually, when you want to do different stuff depending on the type of an object, you just call that object and let it do what it deems reasonable. That’s a good object-oriented way of delegating behavior to objects, totally anti-if campaign compliant and all. But in cases where the object you need to act upon is an incoming DTO, it’s usually not a good approach to put logic on that DTO.
This is a good time to do a “handler lookup” [1. I don’t know if there’s a better name for this pattern. I tried to ask Twitter, but I mostly got “it’s usually not a good idea to do that” – well, most patterns are usually not a good idea: all patterns should be applied only in cases where they make sense
</stating-the-obvious>] in your IoC container for something that can handle an object of the given type. It goes like this: Given
message: T, find
handler: IHandle<T> and invoke
handler with
message.
In C#, that might look like this:
|
void HandleMessage(object message) { var messageType = message.GetType(); var handlerType = typeof(IHandler<>).MakeGenericType(messageType); var handlerInstance = container.Resolve(handlerType); handlerInstance.GetType() .GetMethod("Handle") .Invoke(handlerInstance, new object[] { message }); } |
That’s not too bad I guess, but working at this untyped level for longer than this turns out to be cumbersome and hard to read and understand. It wouldn’t take more than a few lines more of invoking things via reflection before the dispatch of the message has turned into a mess! And then add the fact that exceptions thrown in method invocations made with reflection will be wrapped in
TargetInvocationExceptions.
Consider this alternative approach where I use reflection to invoke a private generic method, closing it with the type of the message:
|
static readonly MethodInfo OpenDispatchMethod = typeof(TheClassWeAreIn).GetMethod("Dispatch", BindingFlags.NonPublic | BindingFlags.Instance); void HandleMessage(object message) { var messageType = message.GetType(); var closedDispatchMethod = OpenDispatchMethod.MakeGenericMethod(messageType); closedDispatchMethod.Invoke(this, new object[] { message }); } void Dispatch<TMessage>(TMessage message) { // whee, we can work with TMessage in here! var handler = container.Resolve<IHandle<TMessage>>(); handler.Handle(message); } |
This way, the
Dispatch method can have the bulk of the logic and it does not need to bother with the reflection API. Nifty!