Is it possible to invoke a general method in a strongly typed way, while maintaining the ability to infer types at compile time?

I have a couple of interfaces that are used to notify request objects and request handlers: -

public interface IQuery<TResponse> { }

public interface IQueryBus
{
  public TResponse Resolve<TResponse>(IQuery<TResponse> query);
}

It should be called in the controller layer as follows: -

FooQuery query = ... // comes from model binding
FooResponse response = this.bus.Resolve(query);

The bus is responsible for finding the request handler: -

public interface IQueryHandler<in TQuery, out TResponse>
  where TQuery : IQuery<TResponse>
{
  public TResponse Handle(TQuery query);
}

Handlers are connected using a dependent converter (I use Ninject, but this should not make much difference).

My current implementation runs in 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 would like to avoid the callMethodInfo.Invoke for stylistic and official purposes.

If I change the signature IQueryBus.Resolveto: -

public TResponse Resolve<TQuery, TResponse>(TQuery query)
  where TQuery : IQuery<TResponse>

Then it's pretty simple to change the implementation: -

var handler = kernel.GetType<IQueryHandler<TQuery, TResponse>>();
return handler.Handle(query);

, , : -

FooResponse response = this.bus.Resolve<FooQuery, FooResponse>(query);

? , : -

  • IQueryBus.Resolve (.. )
  • Query Response Response, Handler (.. )
  • IQueryHandler (.. )

, IQueryBus. , ( , atm).

, , , , , - , .

ShortBus on github, .

+4
3

Queries, TResult, - .

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);
}

, , . , , - , TResponse - . IoC .

+3

: -

interface IQueryHandlerAdapter<TResponse>
{
  TResponse Handle(IQuery<TResponse> query);
}

class QueryHandlerAdapter<TQuery, TResponse>
  where TQuery : class, IQuery<TResponse>
{
  private readonly IQueryHandler<TQuery, TResponse> handler;

  public QueryHandlerAdapter(IQueryHandler<TQuery, TResponse> handler)
  {
    this.handler = handler;
  }

  public TResponse Handle(IQuery<TResponse> query)
  {
    var q = query as TQuery;

    if (q == null)
    {
      throw new InvalidOperationException("...");
    }

    return this.handler.Handle(q);
  }
}

class SynchronousQueryBus
{
  private readonly IKernel kernel;

  public SynchronousQueryBus(IKernel kernel)
  {
    this.kernel = kernel;
  }

  public TResponse Resolve<TResponse>(IQuery<TResponse> query)
  {
    if (query == null)
    {
      throw new ArgumentNullException("query");
    }

    var handler = this.kernel.Get<IQueryHandlerAdapter<TResponse>>();

    return handler.Handle(query);
  }
}

Query/Response . , , IQuery, , , .

, , , , .

+1

, .

public interface Query<TResult> { }
public interface QueryProcessor
{
        TResult Process<TResult>(Query<TResult> query);
}
public interface QueryHandler<in TQuery, out TResult> where TQuery : Query<TResult>
{
        TResult Handle(TQuery query);
}

//GetSomethingByIdQuery Implements : Query<Something>
//so Something will be the return value 
queryProcessor.Process(new GetSomethingByIdQuery());    

//Query Processor
public TResult Process<TResult>(Query<TResult> query)
{
       var handlerType = typeof(QueryHandler<,>)
       .MakeGenericType(query.GetType(), typeof(TResult));

   dynamic handler = _container.Resolve(handlerType);


   return handler.Handle((dynamic)query);
}

public class GetSomethingByIdQueryHandler : QueryHandler<GetSomethingByIdQuery, Something>
{   
    public Something Handle(GetSomethingByIdQuery query)
    {
       using (var session = _store.OpenSession())
      {
        return session.Load<Something >(query.Id)   
      }
    }
} 
0

Source: https://habr.com/ru/post/1525660/


All Articles