5

Le interfacce, i comandi e il gestore di comandi vengono configurati come da istruzioni in Simpleinjector wiki.Uso semplice dell'iniettore per gestore di comandi generici

public interface ICommand 
{ 
    string Name { get; set; } 
} 

public class Command1 : ICommand 
{ 
    public string Name { get; set; } 
} 

public class Command2 : ICommand 
{ 
    public string Name { get; set; } 
} 

public interface ICommandHandler<TCommand> 
{ 
    void Execute(TCommand Command); 
} 

public class Command1Handler : ICommandHandler<Command1> 
{ 
    public void Execute(Command1 Command) { 
     Console.WriteLine(Command.Name); 
    } 
} 

public class Command2Handler : ICommandHandler<Command2> 
{ 
    public void Execute(Command2 Command) { 
     Console.WriteLine(Command.Name + "Hello"); 
    } 
} 

Decorator:

public class CommandDecorator<TCommand> : ICommandHandler<TCommand> 
{ 
    private readonly ICommandHandler<TCommand> _handler; 

    public CommandDecorator(ICommandHandler<TCommand> handler) 
    { 
     this._handler = handler; 
    } 

    public void Execute(TCommand command) 
    { 
     this._handler.Execute(command); 
    } 
} 

Esempio di programma

public class Program 
{ 
    static void Main(string[] args) 
    { 
     Container container = new Container(); 

     //registering 
     container.RegisterAll<ICommand>(typeof(Command1), typeof(Command2)); 

     container.RegisterManyForOpenGeneric(
      typeof(ICommandHandler<>), 
      typeof(ICommandHandler<>).Assembly); 

     container.RegisterDecorator(typeof(ICommandHandler<>), 
      typeof(CommandDecorator<>)); 

     container.Verify(); 

     // sample test command 
     ICommand testcommand = new Command2(); 
     testcommand.Name = "command 1"; 

     var type = typeof(ICommandHandler<>).MakeGenericType(testcommand.GetType()); 

     dynamic instance = container.GetInstance(type); 
     instance.Execute((dynamic)testcommand); 
    } 
} 

E 'questo il modo giusto per ottenere il gestore giusto per gestire il comando in fase di esecuzione. Questo è un esempio e nell'app reale i comandi verranno inviati a una coda e un servizio leggerà il comando e lo elaborerà. Immagino che il decoratore debba essere usato per questo, ma non sono in grado di farlo funzionare. per favore suggerisci opzioni migliori se ce ne sono.

risposta

5

I tuoi comandi (Command1 e Command2) non sono servizi: non devono essere registrati. Sono dati di runtime (messaggio) che si passano attraverso i propri servizi (i gestori dei comandi). Quindi è necessario rimuovere la registrazione RegisterAll<ICommand>. È inutile È già inutile, dal momento che nel tuo esempio stai aggiornando manualmente lo Command2, che è la cosa giusta da fare.

Ciò che si sta facendo nelle ultime tre righe di codice invia un comando di un tipo sconosciuto alla registrazione del gestore comandi di destra. Hai sempre bisogno di un po 'di riflessione per tirare questo, dal momento che è necessario costruire il tipo chiuso ICommandHandler<TCommand> in base al tipo di comando, che è qualcosa che non si conosce in fase di compilazione. Invece di usare la parola chiave C# dynamic, puoi anche utilizzare l'API di riflessione .NET, ma nella mia esperienza l'utilizzo di dynamic è migliore in questo caso particolare. Un importante svantaggio dell'API di reflection è che l'API comprimerà sempre un'eccezione generata (in caso di errore) con uno InvocationException e che rende più difficile eseguire determinate eccezioni nello stack delle chiamate.

Quindi per farla breve, questo dovrebbe essere la tua registrazione:

Container container = new Container(); 

    container.RegisterManyForOpenGeneric(
     typeof(ICommandHandler<>), 
     typeof(ICommandHandler<>).Assembly); 

    container.RegisterDecorator(typeof(ICommandHandler<>), 
     typeof(CommandDecorator<>)); 

E questo dovrebbe essere la logica di dispacciamento:

var type = typeof(ICommandHandler<>).MakeGenericType(command.GetType()); 

    dynamic handler = container.GetInstance(type); 
    handler.Execute((dynamic)command);