有没有办法让C#泛型处理这种情况

时间:2013-11-27 17:07:13

标签: c# generics

当遇到以下情况时,我对使用行

的消费代码感到不满意
var queryResult = _queryDispatcher.Dispatch<CustomerByIdQuery, CustomerByIdQueryResult>(customerByIdQuery).Customer;

我希望代码以这种方式为消费者工作:

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

有没有办法用泛型来实现这个目标?

这是代码

    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;     

    }
  }

以下是我想要的内容:

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

2 个答案:

答案 0 :(得分:3)

是的,这是可能的,但你必须使Dispatch方法的参数通用(这样,编译器可以从方法参数推断出类型参数)。为此,看起来您首先需要IQueryIQueryResult接口的通用版本:

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

接下来,让CustomerByIdQueryCustomerByIdQueryResult实现相应的通用接口:

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;

答案 1 :(得分:0)

我无法摆脱演员,但这与我想要的非常接近。

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