Dynamicznie wywołaj metodę na ogólnym celu

Mam ogólny interfejsICommandHandler<> które będą miały wiele wdrożeń, każda do przetwarzania określonej implementacjiICommandnp .:

public class CreateUserCommand : ICommand { ... }
public class CreateUserCommandHandler : ICommandHandler<CreateUserCommand> { ... }

Kiedy otrzymamICommand obiekt próbuję wysłać go dynamicznie do poprawnegoICommandHandler. W tej chwili zastosowałem całkiem proste podejście do refleksji zInvoke w mojej klasie dyspozytora:

public void Dispatch<T>(T command) where T : ICommand
{
    Type commandType = command.GetType();
    Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
    object handler = IoC.Get(handlerType);
    MethodInfo method = handlerType.GetMethod("Handle");

    method.Invoke(handler, new object[] { command });
}

Istnieją 2 problemy z tym podejściem. Po pierwsze wykorzystuje powolne odbicie. Po drugie, jeśli metoda rzuci jakikolwiek wyjątek, zostanie zapakowana wTargetInvocationException i stracę ślad stosu, jeśli go wyrzucę.

Opracowałem sposób nawiązania połączenia, tworząc delegata i używającDynamicInvoke ale to nie rozwiązuje problemu z wyjątkami (i nie jestem pewienDynamicInvoke jest naprawdę lepszy niżInvoke):

public void Dispatch<T>(T command) where T : ICommand
{
    Type commandType = command.GetType();
    Type handlerType = typeof(ICommandHandler<>).MakeGenericType(commandType);
    object handler = IoC.Get(handlerType);
    MethodInfo method = handlerType.GetMethod("Handle");

    Type actionType = typeof(Action<>).MakeGenericType(commandType);
    Delegate action = Delegate.CreateDelegate(actionType, handler, method);
    action.DynamicInvoke(command);
}

Moje pytanie brzmi: czy jest lepszy sposób na osiągnięcie tego, co próbuję zrobić? Najlepiej byłoby, gdybyśmy zamiast wykonywać ankietę wykonali mocno wpisane połączenieobject i patrząc w góręMethodInfo. Zakładam, że nie jest to możliwe, ponieważ typ nie jest znany w czasie kompilacji.

Jeśli to nie jest możliwe, następnym skutecznym rozwiązaniem będzie wydajne rozwiązanie, które rzuci wyjątek bardziej natywnie.

Edytować: Zaktualizowano próbki kodu, aby wyjaśnić, że używam IoC (Ninject), aby utworzyćICommandHandler w czasie wykonywania, nieActivator.CreateInstance() jak po raz pierwszy umieściłem. Uwzględniono przykład, w jaki sposób zostanie on użyty zgodnie z żądaniem:

var command = new CreateUserCommand() { Name = "Adam Rodger" };
var dispatcher = new CommandDispatcher();
dispatcher.Dispatch(command);
// this would send the message to CreateUserCommandHandler.Handle(command) 
// dynamically and any exceptions would come back 'natively'

Edytuj 2: Jak zasugerowano poniżej, nie mogę rzucić wynikuIoC.Get(handlerType) doICommandHandler<T> bo dostajęInvalidCastException W czasie wykonywania. Dzieje się tak dlatego, że w czasie wykonywaniaT jest aktualneICommandZakładam, że klasy poleceń docierają do WCF i jakoś udaje im się utracić mocne wpisywanie. Kod wywołujący dyspozytora wygląda tak:

[ServiceContract]
public class CommandService
{
    [OperationContract]
    public void Execute(ICommand command) // no type information
    {
        var dispatcher = new CommandDispatcher(); // injected by IoC in real version
        dispatcher.Dispatch(command);
    }
}

questionAnswers(2)

yourAnswerToTheQuestion