簡體   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