用Simple Injector包装泛型类型



问题

我已经有了一个命令处理框架,我正在尝试使用Simple注入器(3.3.2)将我现有的处理程序封装在Mediator能够理解的东西中。我的命令处理程序总是返回CommandResult,所以我的处理程序接口只有TCommand作为Type变量,而Mediator提供的处理程序界面也需要TResult

所以我有一个ICommandHandler<TCommand>和Mediator需要作为IRequestHandler<TRequest, TResult>

思考

我可以将我的ICommandHandler<TCommand>更改为也实现IRequestHandler<TCommand, CommandResult>,但随后我必须将ICommand<TCommand>更改为实现IRequest<TCommand, CommandResult>。但我不想更改现有的代码,并将其紧密地耦合在一起。

我可以在SimpleInjector上截取ResolveUnregisteredType,并返回Mediator需要的任何内容(这将起作用)。但是,我需要依赖于My codeANDMediatorANDSimpleInjector的代码,我希望避免这种情况如果其他一切都失败了,这将是我的后备方案

已尝试

我尝试了三种方法来让注册工作,请参阅代码

代码

这有点像,在顶部的测试中,我希望至少有一个能通过。然后是我现在拥有的接口和TestCommand。在那之后,我尝试了三个地区的东西。

BTW

我不会在这个问题上使用Mediatr标签,因为它可以应用于任何框架。

using MediatR;
using NUnit.Framework;
using SimpleInjector;
using System;
namespace CommandHandlingTest
{
public class Tests
{
[Test]
public void Version_1()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_1(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_1<TestCommand>
}
[Test]
public void Version_2()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_2(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_2<TestCommand, CommandResult>.
}
[Test]
public void Version_3()
{
var container = new Container();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
container.Register(typeof(ICommandHandler<>), assemblies);
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Verify();
var commandBus = new MediatorCommandBus_3(container.GetInstance, container.GetAllInstances);
var command = new TestCommand();
Assert.DoesNotThrow(() => commandBus.Send(command));
// Fails with Handler was not found for request of type CommandWrapped_3<TestCommand, CommandResult>.
}
}
/* Should not change */
public interface ICommand { }

/* Should not change */
public interface ICommandBus
{
CommandResult Send<TCommand>(TCommand command) where TCommand : ICommand;
}
/* Should not change */
public interface ICommandHandler<in TCommand>
where TCommand : ICommand
{
CommandResult Handle(TCommand command);
}
/* Should not change */
public class TestCommand : ICommand { }
/* Should not change */
public class TestHandler : ICommandHandler<TestCommand>
{
public CommandResult Handle(TestCommand command)
{
return new CommandResult { IsValid = true };
}
}
/* Should not change */
public class CommandResult
{
public bool IsValid { get; set; }
}
#region Version 1
public class MediatorCommandBus_1 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_1(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_1<TCommand>(command)).Result;
}
}
public class WrappedHandler_1<TCommand, TResult, TWrappedCommand> :
IRequestHandler<TWrappedCommand, TResult>
where TCommand : ICommand
where TWrappedCommand : CommandWrapped_1<TCommand>, IRequest<TResult>
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_1(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(TWrappedCommand message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_1<TCommand> : IRequest<CommandResult>
where TCommand : ICommand
{
private readonly TCommand _command;
public CommandWrapped_1(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
#endregion
#region Version 2
public class MediatorCommandBus_2 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_2(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_2<TCommand, CommandResult>(command)).Result;
}
}
public class WrappedHandler_2<TCommand, TResult> :
IRequestHandler<CommandWrapped_2<TCommand, TResult>, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_2(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(CommandWrapped_2<TCommand, TResult> message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_2<TCommand, TResult> : IRequest<TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly TCommand _command;
public CommandWrapped_2(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
#endregion
#region Version 3
public class MediatorCommandBus_3 : ICommandBus
{
private readonly IMediator _mediator;
public MediatorCommandBus_3(SingleInstanceFactory singleInstanceFactory, MultiInstanceFactory multiInstanceFactory)
{
_mediator = new Mediator(singleInstanceFactory, multiInstanceFactory);
}
public CommandResult Send<TCommand>(TCommand command)
where TCommand : ICommand
{
return _mediator.Send(new CommandWrapped_3<TCommand, CommandResult>(command)).Result;
}
}
public class WrappedHandler_3<TCommand, TResult> :
IRequestHandler<ICommandWrapped_3<TCommand, TResult>, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly ICommandHandler<TCommand> _commandHandler;
public WrappedHandler_3(ICommandHandler<TCommand> commandHandler)
{
_commandHandler = commandHandler;
}
public TResult Handle(ICommandWrapped_3<TCommand, TResult> message)
{
var handle = _commandHandler.Handle(message.UnWrap());
return handle as TResult;
}
}
public class CommandWrapped_3<TCommand, TResult> : ICommandWrapped_3<TCommand, TResult>
where TCommand : ICommand
where TResult : CommandResult
{
private readonly TCommand _command;
public CommandWrapped_3(TCommand command)
{
_command = command;
}
public TCommand UnWrap() => _command;
}
public interface ICommandWrapped_3<out TCommand, out TResult> : IRequest<TResult>
where TCommand : ICommand
{
TCommand UnWrap();
}
#endregion
}

您应该替换以下行:

container.Register(typeof(IRequestHandler<,>), assemblies);

带有:

container.Register(typeof(IRequestHandler<,>), typeof(WrappedHandler_2<,>));

Register的批注册重载接收程序集列表,默认情况下跳过泛型注册(除非您另有指定),因为泛型类型通常需要特殊处理。在您的情况下,您实际上对批量注册不感兴趣,因为您只有一个感兴趣的映射(即包装处理程序)。

最新更新