Is it possible to invoke a generic method in a strongly-typed fashion while maintaining the ability to infer types at compile-time?
c#, generics, reflection, type-inference
Solution
If there is no possibility to have multiple `Queries` using same `TResult`, then something like this is possible.
public interface IQueryHandler<out TResponse>
{
TResponse Handle(object query);
}
public abstract class QueryHandler<TQuery, TResponse> : IQueryHandler<TResponse>
{
TResponse IQueryHandler<TResponse>.Handle(object query)
{
return Handle((TQuery)query);
}
protected abstract TResponse Handle(TQuery query);
}
public TResponse Resolve<TResponse>(IQuery<TResponse> query)
{
var handlerType = typeof(IQueryHandler<TResponse>);
IQueryHandler<TResponse> handler = kernel.Get(handlerType);
return handler.Handle(query);
}
You might loose typing a little in the middle, but the specific queries and handler are all properly typed just like before. And only performance impact I see is possibility of boxing when `TResponse` is a value type. But that would get overshadowed by IoC looking for the concrete handler.
Problem
I have a couple of interfaces as follows, used to mediate query objects and query handlers:- ``` public interface IQuery<TResponse> { } public interface IQueryBus { public TResponse Resolve<TResponse>(IQuery<TResponse> query); } ``` It's supposed to be invoked in the controller layer as follows:- ``` FooQuery query = ... // comes from model binding FooResponse response = this.bus.Resolve(query); ``` The bus has the responsibility for locating a handler for the query:- ``` public interface IQueryHandler<in TQuery, out TResponse> where TQuery : IQuery<TResponse> { public TResponse Handle(TQuery query); } ``` The handlers are wired up using a dependency resolver (I'm using Ninject, but it shouldn't matter terribly). My current implementation is along the following lines:- ``` public TResponse Resolve(IQuery<TResponse> query) { var queryType = query.GetType(); var handlerType = typeof(IQueryHandler<,>) .MakeGenericType(queryType, typeof(TResponse)); var handleMethod = handlerType.GetMethod("Handle", ...); var handler = kernel.Get(handlerType); return (TResponse)handleMethod.Invoke(handler, new[] { query }); } ``` My problem is that I'd like to avoid the call to `MethodInfo.Invoke` for both stylistic and performance reasons. If I change the signature of `IQueryBus.Resolve` to:- ``` public TResponse Resolve<TQuery, TResponse>(TQuery query) where TQuery : IQuery<TResponse> ``` Then it's pretty simply to change the implementation:- ``` var handler = kernel.GetType<IQueryHandler<TQuery, TResponse>>(); return handler.Handle(query); ``` but then of course the generic type parameters cannot be inferred at the point of use:- ``` FooResponse response = this.bus.Resolve<FooQuery, FooResponse>(query); ``` Can I have my cake and eat it? Is there a solution that satisfies the following:- - Doesn't change the signature of `IQueryBus.Resolve` (i.e. allows its generic type parameters to be inferred) - Allows for compile-time type-safety of the `Query`, the `Response`, and the invocation of the `Handler` (i.e. no reflection or dynamic dispatching) - Doesn't change the interface of `IQueryHandler` (i.e. doesn't expose the handlers to the implementation constraints of the bus) I have control over the rest of the code, I can introduce new types and entirely replace the implementation of `IQueryBus`. I can cache work done by the dependency resolver on app start (which is the most promising lead I have atm). If the worst comes to the worst, then I guess asking the caller to specify the generic type parameters isn't the end of the world, but I'm hoping for something a bit more elegant that minimises the opportunity for future mistakes. There's a pretty similar implementation at ShortBus on github if you're looking for a more complete real-world example.