简体   繁体   English

我如何结合这两个通用接口-ICommand和ICommand的命令处理程序<TResult>

[英]How can I combine these two generic interfaces - command handlers for ICommand and ICommand<TResult>

In my project I have 2 types of commands: 在我的项目中,我有两种类型的命令:

  • Command without result (ICommand) 没有结果的命令(ICommand)
  • Command with result (ICommand) 带结果的命令(ICommand)

Now I have this command handlers: 现在,我有了以下命令处理程序:

public interface ICommandHandler<in TCommand> where TCommand : class, ICommand {
    Task Handle(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
}

public interface ICommandHandler<in TCommand, TResult> where TCommand : class, ICommand<TResult> {
    Task<TResult> Handle(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
}

Question: is it possible to create single ICommandHandler interface for both types of commands? 问题:是否可以为两种类型的命令创建单个ICommandHandler接口?

Before answering - here's a question: Why do you need one interface to include both? 在回答之前-这是一个问题:为什么需要一个界面同时包含两个界面? They are two different interfaces. 它们是两个不同的接口。 If you keep them separate then a class can implement one, the other, or both. 如果将它们分开,则一个类可以实现一个,另一个或两者。 If you already have that flexibility without combining the two interfaces into one, then there may be no benefit from combining them. 如果您已经具有将两个接口合并为一个接口的灵活性,那么将它们组合可能没有任何好处。

Think of it this way: A class is more likely to depend on just one interface or the other. 这样想:类更可能仅依赖一个接口或另一个接口。 It's either going to call the method that returns no result or the method that returns a result. 它要么调用不返回结果的方法,要么返回不返回结果的方法。 (I can't say that for certain, only that it's more likely.) Keeping the interfaces separate allows a class to depend on just the interface it needs and nothing more, which follows the Interface Segregation Principle. (我不能肯定地说,只是它更有可能。)将接口分开可以使类仅依赖其所需的接口,而仅依赖于接口隔离原则。 This is true even if the class implements both interfaces. 即使该类实现了两个接口,也是如此。

Combining also gets a little bit messier because if you want all of the generic type arguments declared at the class level then you really have three generic arguments: TCommand , TResult , and yet another to represent ICommand<TResult> . 合并也会使您有点混乱,因为如果您要在类级别声明所有泛型类型参数,那么您实际上有三个泛型参数: TCommandTResult和另一个用于表示ICommand<TResult>

You could use inheritance so that at least your handler without a TResult stays separate: 您可以使用继承,以便至少没有 TResult的处理程序保持独立:

public interface ICommandHandler<in TCommand>
    where TCommand : class, ICommand
{
    Task Execute(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
}

public interface ICommandHandler<in TCommand, TResult, in TCommandWithResult> : ICommandHandler<TCommand>
    where TCommand : class, ICommand
    where TCommandWithResult : ICommand<TResult>
{
    Task<TResult> GetResult(TCommandWithResult command, CancellationToken cancellationToken = default(CancellationToken));
}

Or, if you really wanted to have them in one interface you could do that: 或者,如果您真的想将它们放在一个界面中,则可以这样做:

public interface ICombinedCommandHandler<in TCommand, TResult, in TCommandWithResult>
    where TCommand : class, ICommand
    where TCommandWithResult : ICommand<TResult>
{
    Task Execute(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
    Task<TResult> GetResult(TCommandWithResult command, CancellationToken cancellationToken = default(CancellationToken));
}

You can eliminate the 3rd generic argument if ICommand<TResult> inherits from ICommand . 如果ICommand<TResult>ICommand继承,则可以消除第3个通用参数。 Perhaps I have a simpler mind than some people, but this approaches the edge of what I call the Generic Rabbit Hole of Madness. 也许我的想法比某些人更简单,但这接近了我所谓的“疯狂兔子洞”的边缘。 At some point I start to wonder, seriously, why am I doing this, and there often isn't a good reason or I can't remember it. 在某个时候,我开始认真地想知道我为什么要这样做,而且通常没有很好的理由,或者我不记得了。

public interface ICommand { }
public interface ICommand<TResult> : ICommand { }

public interface ICommandHandler<in TCommand>
    where TCommand : class, ICommand
{
    Task Execute(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
}

public interface ICommandHandler<in TCommand, TResult> : ICommandHandler<TCommand>
    where TCommand : class, ICommand<TResult>
{
    Task<TResult> GetResult(TCommand command, CancellationToken cancellationToken = default(CancellationToken));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM