4

I have a WCF service that implements a command pattern. Using reflection, I've created a Dictionary where the key is the command type and the value is the CommandHandler. The idea is to receive the command from WCF, using the dictionary to get the handler type, then create an instance of the handler using the activator.

    public CommandResponse RunCommand(Command command)
    {
        _logger.Trace("Running Command");
        var handlerType = HandlerMap[command.GetType()];

        var handler = (AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

        handler.HandleCommand(command);
        return new PostStatCommandResponse();

    }

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

The problem is that Activator.CreateInstance returns an object, not a strongly typed commandhandler. I need to be able to call the HandleCommand, but can't figure out how to cast it to the base AbstractCommandHandler<>

// Syntax error.  Gotta provide type to generic
(AbstractCommandHandler<>)Activator.CreateInstance(handlerType);

// Casting error at run time
(AbstractCommandHandler<Command>)Activator.CreateInstance(handlerType);

// This is dumb and defeats the purpose.
(AbstractCommandHandler<PostStatCommand>)Activator.CreateInstance(handlerType);

Help?

4
  • Is the handler type what in theory be "T" in the AbstractCommandHandler? Commented Aug 31, 2012 at 13:31
  • Have you tried using CreateInstance<T>() instead of CreateInstance(Type)? Commented Aug 31, 2012 at 13:35
  • 1
    CreateInstance<T> still requires the generic argument for the handler. System.Activator.CreateInstance<AbstractCommandHandler<ConcreteType>>(handlerType); Commented Aug 31, 2012 at 13:38
  • @LukeHennerley T in AbstractCommandHandler is the type of command that it handles Commented Aug 31, 2012 at 13:39

3 Answers 3

3

What O. R. Mapper said about interfaces I was implementing and he beat me to the punch, you can cast the generic type to this and then call the method.

  Command c = new PostStatCommand();
  var genericType = typeof(AbstractCommandHandler<>).MakeGenericType(c.GetType());
  ICommandHandler handler = (ICommandHandler)Activator.CreateInstance(genericType);
  handler.HandleCommand(c);

Make the AbstractCommandHandler implement ICommandHandler

 public class AbstractCommandHandler<T> : ICommandHandler
  {
    public void HandleCommand(Command c)
    {
    }
  }

Should work now

Sign up to request clarification or add additional context in comments.

1 Comment

+1 for providing an example of how to use the interface I suggested :-)
2

Why not just call HandleCommand via reflection?

var handler = Activator.CreateInstance(handlerType);
handlerType.GetMethod("HandleCommand").Invoke(handler, new [] {command});

Or, create a non-generic base class (an interface will also do):

public abstract class AbstractCommandHandler
{
    public abstract void HandleCommand(Command command);
}

public abstract class AbstractCommandHandler<T> : AbstractCommandHandler
{
    public override void HandleCommand(Command command)
    {
        HandleCommand((T) command);
    }

    public abstract void HandleCommand(T command);
}

public class StatCommandHandler : AbstractCommandHandler<PostStatCommand>
{

    public override void HandleCommand(PostStatCommand command)
    {

    }
}

and in your RunCommand method:

var handler = Activator.CreateInstance(handlerType);
((AbstractCommandHandler)handler).HandleCommand(command);

1 Comment

I used this solution, except substituted an interface for the first class mentioned.
1

The best possibility will be to provide an interface that uses Command and have your AbstractCommandHandler<> class implement that interface. Something like this:

public interface ICommandHandler
{
    void HandleCommand(Command command);
}

Why? Because passing a Command to HandleCommand is the only thing you can assure. If the command type is not known at design time, a parameter value cannot be checked against it. Therefore, the compiler won't let you cast anything to AbstractCommandHandler<>.

In other words, an argument of type T does not magically become Command just because you leave out the actual type argument for the type. It will simply be unspecified. Also note that AbstractCommandHandler<PostStatCommand> is not a subclass of AbstractCommandHandler<> and thus could not be assigned to a variable of that type.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.