繁体   English   中英

用Simple Injector包装通用类型

[英]Wrapping generic types with Simple Injector

问题

我已经有一个Command处理框架,并且尝试使用简单注入器(3.3.2)将现有的处理程序包装成Mediatr可以理解的东西。 我的命令处理程序始终返回CommandResult因此我的处理程序接口仅将TCommand作为Type变量,而Mediatr提供的处理程序接口也需要TResult

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

关于

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

我可以在ResolveUnregisteredType上拦截ResolveUnregisteredType并返回Mediatr需要的任何东西(这将起作用)。 但是然后我需要依赖于我的代码 Mediatr SimpleInjector的 代码 我想避免这种情况。 如果所有其他方法都失败了,那将是我的后备方案。

试过了

我尝试了三种方法来使注册生效,请参见代码

在最高的测试中,我期望至少有一个测试能够通过。 然后,我现在拥有的接口和一个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的批量注册重载,默认情况下会跳过通用注册(除非另行指定),因为通用类型通常需要特殊处理。 在您的情况下,您实际上对批量注册不感兴趣,因为只有一个您感兴趣的映射(这是包装的处理程序)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM