2017-03-03 63 views
2

我正在實現一個命令處理程序模式,我想創建一個複合命令來解決一些用例。然而,要正確實現此目標,我需要按照http://docs.autofac.org/en/latest/advanced/delegate-factories.html中所述解決代表工廠問題。 但是有一個額外的複雜性,它是通用的...所以我認爲它必須是一個通用的委託工廠,但我無法實現此功能。它看起來很複雜,但我不相信這個功能在AutoFac中不可用。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); 
      } 
     } 
    }   
} 

}

+0

你可能想看看[此要點](https://gist.github.com/default-kramer/f8a8a212d94387741eca#file-autofac-genericsource-cs-L290) - 我創建了名字很差的'GenericSource',使泛型的工作更容易一些。但我不知道它是否仍然適用於最新版本的Autofac。 –

回答

0

至少我已經找到了這個SLOUTION。

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

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); 
     } 
    } 
} 

}