泛型接口的泛型接口

本文关键字:泛型接口 | 更新日期: 2023-09-27 17:50:44

我的问题中有很多泛型,我希望它仍然是可以理解的…

我有以下接口:

public interface ICommandBus
{
    TResult Publish<TCommand, TResult>(TCommand command)
        where TResult : ICommandResult
        where TCommand : ICommand<TResult>;
}
public interface ICommand<T>
    where T : ICommandResult
{ }
public interface ICommandResult
{
    bool Success { get; }
}

我想用这种方式使用他们的实现(我提交CommandBus,它对这个问题没用,但你可以在这里找到它):

public class CreateItemCommand: ICommand<CreateItemResult>
{
    public string Name { get; private set; }
}
public class CreateItemResult: ICommandResult
{
    public bool Success { get; private set; }
}
var command = new CreateItemCommand();
var result = commandBus.Publish(command); //Error here

我有错误:The type arguments cannot be inferred from the usage。我已经尝试了一些in和out修饰符,没有成功…

我如何调用我的Publish方法,而不指定参数类型,像这样:

var result = commandBus.Publish<CreateItemCommand, CreateItemResult>(command); //Works, but ugly...

EDIT: update for Lucas answer

卢卡斯解决方案应该工作,但我仍然必须把where TResult : ICommandResult约束,以避免错误There is no boxing conversion or type parameter conversion from 'TResult' to 'Core.Command.ICommandResult'

我也有一个巨大的继承问题,让我们说我有以下抽象的CommandObserver:

public abstract class NotificationObserver<TResult> : ICommandObserver<TResult>
    where TResult : ICommandResult
{
    protected virtual bool IsEnable(ICommand<TResult> command, TResult result)
    {
        return true;
    }
}

它的实现

public class CreateItemObserver : NotificationObserver<CreateItemResult>
{
    protected override bool IsEnable(CreateItemCommand command, CreateItemResult result)
    {
        return !String.IsNullOrEmpty(command.Name);
    }
}

这将不起作用,因为实现并没有真正覆盖虚拟方法(不是相同的签名:ICommand<TResult> != CreateItemCommand)。

如果我保持正确的签名,我不能使用CreateItemCommand属性没有一个丑陋的强制转换在实现…

泛型接口的泛型接口

您可以像这样轻松地重写您的界面,以摆脱TCommand参数:

public interface ICommandBus
{
    TResult Publish<TResult>(ICommand<TResult> command)
        where TResult : ICommandResult;
}
注意,您也可以删除where TResult : ICommandResult,因为这个约束与ICommand<TResult>中的定义是冗余的:
public interface ICommandBus
{
    TResult Publish<TResult>(ICommand<TResult> command);
}

我猜c#拒绝推断类型参数的原因是TCommand可以多次实现ICommand<T>,像这样:

public class SomeCommand : ICommand<Foo>, ICommand<Bar>
{
    // ...
}

我看到一个泛型过量;)太多的泛型,而简单的继承会给你更容易的结果。

如果你想在不完全重构的情况下使用你的类来摆脱太多的泛型:你只需要指定泛型函数调用,因为编译器没有足够的智能来为你做这件事(自动解析一个泛型参数是可以的,解析一个泛型参数的泛型参数是不行的)。

var result = commandBus.Publish<CreateItemCommand, CreateItemResult>(command); 

它很重,它不是特别优雅,但至少它能工作。顺便说一句,你的接口声明本身很重,所以使用它也很重也就不足为奇了。