Мы начнем с отдельной истории, просто чтобы вы поняли, почему: я хочу рассматривать любые действия, которые изменяют данные, в одном и том же интерфейсе: ICommand Существуют вещи, называемые ICommandHandlers, которые обрабатывают любую команду, которую я захочу. Итак, если я хочу CreatePersonCommand, мне нужен CreatePersonCommandHandler.
Итак, вот тело консольного приложения, которое демонстрирует это: (Требуется Simple Injector)
// The e.g. CreatePersonCommand, with TResult being Person, as an example.
public interface ICommand<TResult>
{
}
//This handles the command, so CreatePersonCommandHandler
public interface ICommandHandler<in TCommand, out TResult>
where TCommand : ICommand<TResult>
{
TResult Handle(TCommand command);
}
// Imagine a generic CRUD set of operations here where we pass
// in an instance of what we need made
public class CreateBaseCommand<TModel> : ICommand<TModel>
{
public TModel ItemToCreate { get; set; }
}
public class DeleteBaseCommand<TModel> : ICommand<TModel>
{
public TModel ItemToDelete { get; set; }
}
public class CreateCommandBaseHandler<TModel>
: ICommandHandler<CreateBaseCommand<TModel>, TModel>
{
public TModel Handle(CreateBaseCommand<TModel> command)
{
// create the thing
return default (TModel);
}
}
public class DeleteCommandBaseHandler<TModel>
: ICommandHandler<DeleteBaseCommand<TModel>, TModel>
{
public TModel Handle(DeleteBaseCommand<TModel> command)
{
// delete the thing
return default(TModel);
}
}
public class Program
{
private static Container container;
static void Main(string[] args)
{
container = new Container();
// Order does not seem to matter, I've tried both ways.
container.RegisterOpenGeneric(typeof(ICommandHandler<,>),
typeof(DeleteCommandBaseHandler<>));
container.RegisterOpenGeneric(typeof(ICommandHandler<,>),
typeof(CreateCommandBaseHandler<>));
container.Verify();
// So I want to make the usual hello world
var commandToProcess = new CreateBaseCommand<string> { ItemToCreate = "hello world"};
// Send it away!
Send(commandToProcess);
}
private static void Send<TResult>(ICommand<TResult> commandToProcess)
{
//{CreateBaseCommand`1[[System.String,..."}
var command = commandToProcess.GetType();
//{Name = "String" FullName = "System.String"}
var resultType = typeof (TResult);
//"ICommandHandler`2[[CreateBaseCommand`1[[System.String,..."}
// so it's the right type here
var type = typeof(ICommandHandler<,>).MakeGenericType(command, resultType);
// This is where we break!
var instance = container.GetInstance(type);
// The supplied type DeleteCommandBaseHandler<String> does not implement
// ICommandHandler<CreateBaseCommand<String>, String>.
// Parameter name: implementationType
}
}
Поэтому по какой-то причине SimpleInjector всегда пытается разрешить DeleteCommandHandler<>
для CreateBaseCommand<>
, которые у меня есть. Опять же, порядок не имеет значения. У меня есть другие обработчики команд закрытого типа (и соответствующие им команды), которые просто наследуют ICommandHandler<,>
и работают нормально.
Я провел немало времени, изучая все возможные типы регистрации, какие мог, из этого.