Is there a way to make C # generics handle this script

Given the following scenario, I’m not happy with the consumption code, which is dotted with a line

var queryResult = _queryDispatcher.Dispatch<CustomerByIdQuery, CustomerByIdQueryResult>(customerByIdQuery).Customer;

I would prefer the code to work this way for the consumer:

var queryResult = _queryDispatcher.Dispatch(customerByIdQuery).Customer;

Is there a way to accomplish this with generics?

Here is the code

    interface IQuery{}
    interface IQueryResult{}

    interface IQueryHandler<TQuery, TQueryResult> : where TQueryResult:IQueryResult  where TQuery:IQuery
    {
      TQueryResult Execute(TQuery query);
    }

    interface IQueryDispatcher
    {
      TQueryResult Dispatch<TQuery, TQueryResult>(TQuery query) where TQuery:IQuery where TQueryResult:IQueryResult
    }

    class GenericQueryDispatcher : IQueryDispatcher
    {
      public TQueryResult Dispatch<TQuery, TQueryResult>(TQuery parms)
      {
        var queryHandler = queryRegistry.FindQueryHandlerFor(TQuery);
        queryHandler.Execute
      }
    }

    class CustomerByIdQuery : IQuery
    {
      public int Id { get; set; }
    }

    class CustomerByIdQueryResult : IQueryResult
    {
      public Customer {get; set;}
    }

    class CustomerByIdQueryHandler : IQueryHandler
    {
      public CustomerByIdQueryResult  Execute(TQuery query)
      {
        var customer = _customerRepo.GetById(query.Id);
        return new CustomerByIdQueryResult(){Customer = customer};
      }
    }


  public class SomeClassThatControlsWorkFlow
  {
    IQueryDispatcher _queryDispatcher;

    public SomeClassThatControlsWorkFlow(IQueryDispatcher queryDispatcher)
    {
      _queryDispatcher = queryDispatcher;
    }

    public void Run()
    {
      var customerByIdQuery = new CustomerByIdQuery(){Id=1};
      //want to change this line
      var customer = _queryDispatcher.Dispatch<CustomerByIdQuery, CustomerByIdQueryResult>(customerByIdQuery).Customer;     

    }
  }

Here is what I would like to have:

public class ClassWithRunMethodIWouldLikeToHave
  {
    IQueryDispatcher _queryDispatcher;

    public SomeClassThatControlsWorkFlow(IQueryDispatcher queryDispatcher)
    {
      _queryDispatcher = queryDispatcher;
    }

    public void Run()
    {
      var customerByIdQuery = new CustomerByIdQuery(){Id=1};
      //want to change this line
      var customer = _queryDispatcher.Dispatch(customerByIdQuery).Customer;     
    }
  }
+4
source share
2 answers

Yes, it is possible, but you must make the parameter of the method Dispatchgeneric (in this way, the compiler can infer type parameters from the parameter of the method). To do this, it looks like you will first need a generic version of the interfaces IQueryand IQueryResult:

interface IQuery<TQuery, TQueryResult> : IQuery {}
interface IQueryResult<T> : IQueryResult 
{ 
    T Result { get; }
}

Then create CustomerByIdQueryand CustomerByIdQueryResultimplement the corresponding common interfaces:

class CustomerByIdQuery : IQuery, IQuery<int, Customer>
{
  public int Id { get; set; }
}
class CustomerByIdQueryResult : IQueryResult, IQueryResult<Customer>
{
  public Customer Result {get; set;}
}

Dispatch, :

interface IQueryDispatcher
{
    IQueryResult<TQueryResult> Dispatch<TQuery, TQueryResult>(IQuery<TQuery, TQueryResult> parms);
}

class GenericQueryDispatcher : IQueryDispatcher
{
  public TQueryResult Dispatch<TQuery, TQueryResult>(IQuery<TQuery, TQueryResult> parms)
  {
    // TODO implement
  }
}

:

var customerByIdQuery = new CustomerByIdQuery{Id=1};
var customer = _queryDispatcher.Dispatch(customerByIdQuery).Result;
+3

, , .

    public interface IQueryDispatcher
  {
    TQueryResult Dispatch<TParameter, TQueryResult>(IQuery<TQueryResult> query)
      where TParameter : IQuery<TQueryResult>
      where TQueryResult : IQueryResult;
  }
  public interface IQueryHandler<in TQuery, out TQueryResult>
    where TQuery : IQuery<TQueryResult>
    where TQueryResult : IQueryResult
  {
    TQueryResult Retrieve(TQuery query);
  }


  public interface IQueryResult { }



  public interface IQuery { }
  public interface IQuery<TQueryResult> : IQuery { }


  public class QueryDispatcher : IQueryDispatcher
  {
    readonly IQueryHandlerRegistry _queryRegistry;

    public QueryDispatcher(IQueryHandlerRegistry queryRegistry)
    {
      _queryRegistry = queryRegistry;
    }

    public TQueryResult Dispatch<TQuery, TQueryResult>(IQuery<TQueryResult> query)
      where TQuery : IQuery<TQueryResult>
      where TQueryResult : IQueryResult
    {
      var handler = _queryRegistry.FindQueryHandlerFor<TQuery, TQueryResult>(query);

       //CANT GET RID OF CAST
      return handler.Retrieve((TQuery)query);
    }
  }

  public interface IQueryHandlerRegistry
  {
    IQueryHandler<TQuery, TQueryResult> FindQueryHandlerFor<TQuery, TQueryResult>(IQuery<TQueryResult> query) 
      where TQuery : IQuery<TQueryResult> 
      where TQueryResult : IQueryResult;
  }

  public class GetCustByIdAndLocQuery : IQuery<CustByIdAndLocQueryResult>
  {
    public string CustName { get; set; }
    public int LocationId { get; set; }

    public GetCustByIdAndLocQuery(string name, int locationId)
    {
      CustName = name;
      LocationId = locationId;
    }
  }

  public class CustByIdAndLocQueryResult : IQueryResult
  {
    public Customer Customer { get; set; }
  }

  public class GetCustByIdAndLocQueryHandler : IQueryHandler<GetCustByIdAndLocQuery, CustByIdAndLocQueryResult>
  {
    readonly ICustomerGateway _customerGateway;

    public GetCustByIdAndLocQueryHandler(ICustomerGateway customerGateway)
    {
      _customerGateway = customerGateway;
    }

    public CustByIdAndLocQueryResult Retrieve(GetCustByIdAndLocQuery query)
    {
      var customer = _customerGateway.GetAll()
                        .SingleOrDefault(x => x.LocationId == query.LocationId && x.CustomerName == query.CustName);

      return new CustByIdAndLocQueryResult() { Customer = customer };
    }
  }

  public interface ICustomerGateway
  {
    IEnumerable<Customer> GetAll();
  }

  public class Customer
  {
    public string CustomerName { get; set; }
    public int LocationId { get; set; }

    public bool HasInsurance { get; set; }
  }
0

All Articles