The trick is to make the interface generic:
public interface IMessageHandler{ void Handle(T message); } public class MonkeyHandler : IMessageHandler { public void Handle(Monkey message) {} }
To resolve a handler simply do:
var monkeyHandler = yourContainer.Resolve>();
The problem with that is if you receive messages as object
you can't do a transition from object to generics at compile time.
object message = endPoint.Recieve(); //not fun to do this: if (message is Monkey) container.Resolve>((Monkey)message);
Instead you need to do a transition from objects to typed handlers.
public interface IMessageHandler { void Handle(object message); } public interface IMessageHandler: IMessageHandler { void Handle(T message); } public class MonkeyHandler : IMessageHandler { public void Handle(Monkey message) {} //hide from the public API void IMessageHandler.Handle(object message) { Handle((Monkey)message); } }
.. which means that you can now locate it using a Type
:
var genericInterfaceType = typeof(IMessageHandler<>).MakeGenericType(message.GetType()); var handlerObj = container.Resolve(genericInterfaceType);
.. so that you can cast it to the base interface and invoke it:
var handler = (IMessageHandler)handlerObj; handler.Handle(message);
yay. We got a GOAL!
To remove the repetitive task of transitioning from objects to typed in the handlers you could create a base class:
public abstract class HandlerBase: IMessageHandler { public abstract void Handle(Monkey message); void IMessageHandler.Handle(object message) { Handle((T)message); } } public class MonkeyHandler : HandlerBase { public override void Handle(Monkey message) { } }