我正在尝试使用我的命令和一些通用方法。我没有那么多使用仿制药,所以现在我的大脑都搞砸了,希望得到一些帮助。
我想要的是最后一次通过测试。返回我的TResult而不需要在电话中提供TCommand,TResult。
invoker.Execute(command)
由于该命令实现
: CommandBase<TestResult>
我认为编译器会解决这个问题。
但是编译器只将我带到了void方法。
提前非常感谢!
编辑:完整代码位于:http://codepaste.net/7rjg2e
CommandInvoker
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; }
}
CommandHandler
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));
}
答案 0 :(得分:2)
这是来自语言规范中的类型推断规则。
约束where TCommand : ICommand<TResult>
在确定推断类型时不起作用。
因此,类型推断算法仅使用
Execute<TComamnd, TResult>(TCommand command)
推断出TResult
的类型。但参数TCommand command
中没有信息来确定类型TResult
。
因此,过载
TResult Execute<TCommand, TResult>(TCommand command)
不是适用的函数成员,因为它无法找出TResult
。
从7.5.2开始
如果特定方法的类型推断失败,则该方法不参与重载解析。
此处,TResult
的类型推断失败。
答案 1 :(得分:1)
除非将TResult作为参数传入,否则编译器无法确定TResult是什么。它能够确定TCommand的类型是什么,因为传入了它。
我没有看到你需要TCommand的任何理由,你有一个足够好的接口,你需要通用的唯一地方是返回,作为建议尝试改变ICommandInvoker的签名,它将给你你想要什么:
public interface ICommandInvoker
{
void Execute(ICommand command);
TResult Execute<TResult>(ICommand<TResult> command);
}
编辑:
实际上我确实知道你为什么要TCommand,因为你在容器上使用泛型类型,但我的答案仍然存在。您可以将Type传递给容器而不是通用吗?
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;
}