通用接口与泛型的通用接口

时间:2015-05-25 16:07:53

标签: c# generics

我的问题中有很多仿制药,我希望它仍然可以理解......

我有以下界面:

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,它对这个问题没用,但你可以找到它here):

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。 我已尝试使用inout修饰符但未成功...

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

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

编辑:卢卡斯回答的更新

Lucas解决方案应该可行,但我仍然必须设置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属性而不会在实现中使用丑陋的演员......

2 个答案:

答案 0 :(得分:4)

您可以轻松地重写您的界面,以摆脱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>
{
    // ...
}

答案 1 :(得分:1)

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

如果你想使用你的类而不完全重构以摆脱太多的泛型:你只需要指定泛型函数调用,因为编译器不够智能,无法为你做这件事(自动解析一般参数很好,解析泛型参数的泛型参数不是。

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

它很重,它不是特别优雅,但至少它有效。另外,你的界面声明很重,所以使用它也不会太令人惊讶。

相关问题