泛型方法调用,不想发送我的类型



我正在试验我的命令和一些通用方法。我没怎么用仿制药,所以现在我的大脑一团糟,希望能得到一些帮助。

我想要的是通过最后一个测试。然后返回我的TResult,而无需我在调用中提供TCommand和TResult。

invoker.Execute(command)

由于该命令实现

: CommandBase<TestResult>

我以为编译器会解决的。

但是编译器只带我去void方法。

非常感谢!

编辑:完整的代码位于:http://codepaste.net/7rjg2e

命令调用程序

public interface ICommandInvoker
{
    void Execute<TCommand>(TCommand command) where TCommand : ICommand;
    TResult Execute<TCommand, TResult>(TCommand command) where TCommand : ICommand<TResult>;
}
public class CommandInvoker : ICommandInvoker
{
    ...
    public void Execute<TCommand>(TCommand command) where TCommand : ICommand
    {
        var handler = _container.GetInstance<ICommandHandler<TCommand>>();
        handler.Handle(command);
        _session.SaveChanges();
    }
    public TResult Execute<TCommand, TResult>(TCommand command) where TCommand : ICommand<TResult>
    {
        var handler = _container.GetInstance<ICommandHandler<TCommand>>();
        handler.Handle(command);
        return command.Result;
    }
}

命令

public interface ICommand
{
    bool IsValid { get; }
}
public interface ICommand<TResult> : ICommand
{
    TResult Result { get; }
}
public class CommandBase : ICommand
{
    public bool IsValid
    {
        get { return false; }
    }
}
public class CommandBase<TResult> : ICommand<TResult>
{
    public bool IsValid { get { return false; } }
    public TResult Result { get; set; }
}

命令处理程序

public interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}
public interface ICommandHandlerWithResult<TCommand, TResult> where TCommand : ICommand<TResult>
{
    void Handle(TCommand command);
}

测试类

public class TestCommandWithResult : CommandBase<TestResult>
{
    public string Id { get; set; }
}
public class TestResult
{
    public string Message { get; set; }
}

测试有效

[Test]
public void CanExcecuteWithResult()
{
    var command = new TestCommandWithResult { Id = "billy" };
    ObjectFactory.ResetDefaults();
    var mockHandler = new Mock<ICommandHandler<TestCommandWithResult>>();
    var sessionMock = new Mock<ISession>();
    ObjectFactory.Configure(x => x.For<ICommandHandler<TestCommandWithResult>>().Use(mockHandler.Object));
    var invoker = new CommandInvoker(ObjectFactory.Container, sessionMock.Object);
    var result = invoker.Execute<TestCommandWithResult, TestResult>(command);
    mockHandler.Verify(x => x.Handle(command));
}

我想通过的测试

    [Test]
    public void CanExcecuteWithResult()
    {
        var command = new TestCommandWithResult { Id = "billy" };
        ObjectFactory.ResetDefaults();
        var mockHandler = new Mock<ICommandHandler<TestCommandWithResult>>();
        var sessionMock = new Mock<ISession>();
        ObjectFactory.Configure(x => x.For<ICommandHandler<TestCommandWithResult>>().Use(mockHandler.Object));
        var invoker = new CommandInvoker(ObjectFactory.Container, sessionMock.Object);
        var result = invoker.Execute(command); // <-- this only calls void version
        mockHandler.Verify(x => x.Handle(command));
    }

这来自语言规范中的类型推理规则。

约束CCD_ 1在确定推断类型中不起作用。

因此,类型推理算法只使用

Execute<TComamnd, TResult>(TCommand command)

以推断CCD_ 2的类型。但是在参数CCD_ 3中没有用于确定类型CCD_。

因此,过载

TResult Execute<TCommand, TResult>(TCommand command)

不是适用的函数成员,因为它无法计算TResult

自7.5.2

如果特定方法的类型推理失败,则该方法不参与重载解析。

这里,TResult的类型推断失败。

除非TResult作为参数传入,否则编译器无法计算出TResult是什么。它能够计算出TCommand的类型是什么,因为它是传入的

我看不出你需要TCommand的任何原因,你有一个足够好的接口,你唯一需要泛型的地方是在返回上。作为一个建议,尝试更改ICommandInvoker的签名,这将给你想要的:

public interface ICommandInvoker
{
    void Execute(ICommand command);
    TResult Execute<TResult>(ICommand<TResult> command);
}

编辑:

事实上,我确实明白你为什么想要TCommand,因为你在容器上使用泛型类型,但我的答案仍然有效。你能把类型而不是泛型传递给你的容器吗?

public TResult Execute<TResult>(ICommand<TResult> command)
{
    Type commandHandlerType = typeof(ICommandHandler<>).MakeGenericType(command.GetType());
    var handler = _container.GetInstance(commandHandlerType);
    handler.Handle(command);
    return command.Result;
}

最新更新