簡體   English   中英

Autofac Register通用代理工廠

[英]Autofac Register Generic Delegate factory

我正在實現一個命令處理程序模式,我想創建一個復合命令來解決一些用例。 但是,要正確實現此目的,我需要解析http://docs.autofac.org/en/latest/advanced/delegate-factories.html中所述的委托工廠。 但是還有一個額外的復雜性,它是泛型的...因此,我認為它必須是泛型的委托工廠,但我無法實現此功能。 它看起來很復雜,但是我無法相信AutoFac中沒有此功能。

我在https://gist.github.com/robvanpamel/2aa2b27da8d0f922b9b98b6331b2e57f單元測試失敗的情況下創建了問題要點。

有誰可以幫助我嗎?

using System;
using System.Collections.Generic;
using Xunit;
using Autofac;
namespace Tests
{
public class Tests
{
    public class ClassUnderTest
    {
        public IContainer CreateContainer()
        {
            var builder = new Autofac.ContainerBuilder();
            builder.RegisterType<MyCommandHandler>().As<ICommandHandler<AnotherCommand>>();
            builder.RegisterType<MyCommandHandler>().As<ICommandHandler<MyCommand>>();
            builder.RegisterGeneric(typeof(CompositeCommandHandler<>)).As(typeof(ICommandHandler<>));

            // How to register this ???  
            //builder.Register<Func<ICommand, ICommandHandler<ICommand>>>(c => s => c.Resolve(s)));

            return builder.Build();
        }
    }

    [Fact]
    public void Test1()
    {
        // arrange 
        var myClassUnderTest = new ClassUnderTest();
        var container = myClassUnderTest.CreateContainer();
        var myCommand = new MyCompositeCommand(new List<ICommand> { new MyCommand(), new AnotherCommand() });

        // act 
        Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<MyCommand>>());
        Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<AnotherCommand>>());
        var handler = container.Resolve<ICommandHandler<MyCompositeCommand>>();

        handler.Handle(myCommand);
    }
    public interface ICommand { }

    public interface ICompositeCommand : ICommand
    {
        IEnumerable<ICommand> Commands { get; }
    }
    public class MyCommand : ICommand { }
    public class AnotherCommand : ICommand { }
    public class MyCompositeCommand : ICompositeCommand
    {
        private readonly IEnumerable<ICommand> commands;
        public MyCompositeCommand(IEnumerable<ICommand> commands)
        {
            this.commands = commands;
        }
        public IEnumerable<ICommand> Commands { get { return commands; } }
    }
    public interface ICommandHandler<T> where T : ICommand
    {
        void Handle(T command);
    }

    public class MyCommandHandler : ICommandHandler<MyCommand>, ICommandHandler<AnotherCommand>
    {
        public void Handle(MyCommand command)
        {
            Console.WriteLine("Handling MyCommand");
        }

        public void Handle(AnotherCommand command)
        {
            Console.WriteLine("Handling AnotherCommand");
        }
    }

    public class CompositeCommandHandler<CompositeCommand> : ICommandHandler<CompositeCommand> where CompositeCommand : ICompositeCommand
    {
        private Func<ICommand, ICommandHandler<ICommand>> _factory;
        public CompositeCommandHandler(Func<ICommand, ICommandHandler<ICommand>> factory)
        {
            _factory = factory;
        }

        public void Handle(CompositeCommand command)
        {
            foreach (var myCommand in command.Commands)
            {
                var handler = _factory(myCommand);
                handler.Handle(myCommand);
            }
        }
    }        
}

}

至少我發現了這一點。

這不是我想的最好方法,但是它正在運行。

using System;
using System.Collections.Generic;
using Xunit;
using Autofac;
using System.Reflection;

namespace Tests
{
public class Tests
{
    public class ClassUnderTest
    {
        public IContainer CreateContainer()
        {
            var builder = new Autofac.ContainerBuilder();
            builder.RegisterType<MyCommandHandler>().As<ICommandHandler<AnotherCommand>>();
            builder.RegisterType<MyCommandHandler>().As<ICommandHandler<MyCommand>>();
            builder.RegisterGeneric(typeof(CompositeCommandHandler<>)).As(typeof(ICommandHandler<>));

            return builder.Build();
        }
    }

    [Fact]
    public void Test1()
    {
        // arrange 
        var myClassUnderTest = new ClassUnderTest();
        var container = myClassUnderTest.CreateContainer();
        var myCommand = new MyCompositeCommand(new List<ICommand> { new MyCommand(), new AnotherCommand() });

        // act 
        Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<MyCommand>>());
        Assert.IsType<MyCommandHandler>(container.Resolve<ICommandHandler<AnotherCommand>>());
        var handler = container.Resolve<ICommandHandler<MyCompositeCommand>>();

        handler.Handle(myCommand);
    }
    public interface ICommand { }

    public interface ICompositeCommand : ICommand
    {
        IEnumerable<ICommand> Commands { get; }
    }
    public class MyCommand : ICommand { }
    public class AnotherCommand : ICommand { }
    public class MyCompositeCommand : ICompositeCommand
    {
        private readonly IEnumerable<ICommand> commands;
        public MyCompositeCommand(IEnumerable<ICommand> commands)
        {
            this.commands = commands;
        }
        public IEnumerable<ICommand> Commands { get { return commands; } }
    }

    public interface ICommandHandler<in T> where T : ICommand
    {
        void Handle(T command);
    }

    public class MyCommandHandler : ICommandHandler<MyCommand>, ICommandHandler<AnotherCommand>
    {
        public void Handle(MyCommand command)
        {
            Console.WriteLine("Handling MyCommand");
        }

        public void Handle(AnotherCommand command)
        {
            Console.WriteLine("Handling AnotherCommand");
        }
    }

    public class CompositeCommandHandler<CompositeCommand> : ICommandHandler<CompositeCommand> where CompositeCommand : ICompositeCommand
    {
        private Func<ICommand, ICommandHandler<ICommand>> _factory;

        private ILifetimeScope _container;
        public CompositeCommandHandler(ILifetimeScope container)
        {
            _container = container;
        }

        public void Handle(CompositeCommand command)
        {

            foreach (var myCommand in command.Commands)
            {
                // resolve the specific command handler
                var handler = ResolveMyHandler(myCommand);

                // invoke the command handler
                var handlerType = handler.GetType();
                var handleMethod = handlerType.GetMethod(nameof(ICommandHandler<ICommand>.Handle),new []{myCommand.GetType()}); 
                handleMethod.Invoke(handler, new[]{ myCommand}); 
            }
        }

        public object ResolveMyHandler(ICommand command)
        {
            var mySpecificHandlerType = command.GetType();
            var myGenericCommandHandlerType = typeof(ICommandHandler<>);
            var result = myGenericCommandHandlerType.MakeGenericType(new[] { mySpecificHandlerType });
            return _container.Resolve(result);
        }
    }
}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM