简体   繁体   中英

Passing the Class Type instead of the Interface through Generics

OK I've just implemented a Command-CommandHandler pattern in our application that adds a command object to a queue; then uses dependency injection through Castle Windsor alongside a generic method to get the relevant handler for the command object.

The Command interface is blank like so:

public interface ICommand
{
}

Whilst the CommandHandler interface handles it like so:

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

These are then implemented by the commands I wish to send through the queue; then registered in Castle Windsor through a DependencyRegistration wrapper like so:

_dependencyRegister
    .AddRegistration<ICommandHandler<TestCommand>, TestCommandHandler>();

So each command that will be added to the queue maps 1 to 1 with a handler; then is registered in Castle Windsor; so we can use a generic method like this to get the relevant CommandHandler for a particular Command object:

private void HandleCommand<T>(T queueItem) where T: ICommand
{
    var handler = _dependencyResolver.Resolve<ICommandHandler<T>>();

    handler.Handle(queueItem);
}

The final piece is the queue dispatcher method which looks like this:

private void DispatchQueueItem(ICommand queueItem)
{
    HandleCommand(queueItem);
}

Right; the issue is that when I pull a command off the queue as an ICommand and pass it to the DispatchQueueItem method; when it is sent to the HandleCommand method the "T" type is always set to the "ICommand" interface; rather than the actual implementation of the interface (TestCommand in the DependencyRegistration sample code).

My question is; how do I set the HandleCommand method to take the Type of the implementation; not the interface?

Change your dispatch method to generic:

private void DispatchQueueItem<T>(T queueItem)
    where T: ICommand
{
    HandleCommand(queueItem);
}

UPDATE you can force C# to define object type at runtime this way

private static void DispatchQueueItem(ICommand queueItem)
{
    HandleCommand((dynamic)queueItem);
}

I think you want it to be of the interface - but you just need to have a method contract defined in there - like:

public interface ICommand
{
    void Execute();
}

//Concrete implementation:
public TestCommand : ICommand
{
    public void Execute()
    {
        //Do something
    }
}

Then, when you get the ICommand out of DI - you can call queueItem.Execute() - and this will refer to whatever concrete implementation you've assigned.

Yout queue will lalways dispatch ICommands. So so need to get the type "under the hood":

private void HandleCommand<T>(T queueItem) where T: ICommand
{
  var typeParam = queueItem.GetType();
  var type = typeof(ICommandHandler<>).MakeGenericType(typeParam);
  var handler = _dependencyResolver.Resolve(type);

I'm not sure of the exact sintax. Don't have a project with Castle Windsor at hand.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM