2017-03-03 3 views
2

Ich bin ein Befehlshandler-Muster implementieren und ich möchte einen zusammengesetzten Befehl erstellen, um einige Anwendungsfälle zu lösen. Um dies jedoch richtig zu erreichen, muss eine Delegiertenfabrik wie in http://docs.autofac.org/en/latest/advanced/delegate-factories.html beschrieben aufgelöst werden. Allerdings gibt es eine zusätzliche Komplexität, es ist generisch ... Also ich nehme an, es muss eine generische Delegate Factory sein, aber ich bin nicht in der Lage, diese Funktionalität zu erreichen. Es sieht kompliziert aus, aber ich kann nicht glauben, dass diese Funktionalität in AutoFac nicht verfügbar ist.Autofac-Register Generische Delegat-Fabrik

Ich habe einen Kern meines Problems mit einem fehlerhaften Komponententest bei https://gist.github.com/robvanpamel/2aa2b27da8d0f922b9b98b6331b2e57f erstellt.

Gibt es jemanden, der mir helfen könnte?

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

Sie vielleicht einen Blick auf [dieser Kern] nehmen wollen (https://gist.github.com/default-kramer/f8a8a212d94387741eca#file-autofac-genericsource-cs-L290) - Ich habe die schlecht benannte 'GenericSource' erstellt, um das Arbeiten mit Generika etwas einfacher zu machen. Aber ich weiß nicht, ob es immer noch mit der neuesten Version von Autofac funktioniert. –

Antwort

0

Wenigstens habe ich eine sloution dafür gefunden.

es ist nicht der beste Weg, nehme ich an, aber es läuft.

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

}

Verwandte Themen