Reputation: 32684
I have an interface method
public void Execute(ICommand command);
which needs to pass known subtypes of ICommand
to an apropriate Handle(SpecificCommand command)
method implementation and do some generic handling of unknown types. I am looking for a universal (i.e. not requiring a giant switch) method of doing so, something similar to
Handle(command as command.GetType()); // this obviously does not compile
I know I could register the handlers somehow, e.g. store them as delegates in a dictionary, but this still requires duplicating the handling logic (once in the specific Handle(...)
method signature, once in the delegate reqistration). If I populate the dictionary by inspecting my class with reflection (looking for Handle(XXX command)
methods), I'll get a performance hit.
To summarize: how can I downcast an object (upcasted by the call to Execute(ICommand command)
) to invoke a method requiring a concrete type without knowing which type it is at compile time.
Upvotes: 1
Views: 1914
Reputation: 103495
I've tried working out a way which would work using Double Dispatch (http://en.wikipedia.org/wiki/Double_dispatch), but it seems that you have a situation where the number of classes implementing ICommand and those implementing Execute() can vary at run-time (or, at least between compile & run-time, which is essentially the same thing), so the only solution I can see it use the dictionary as Jon Skeet propsed.
Upvotes: 1
Reputation: 1500155
The cast is emitted at compile-time, so you need to know the type at compile-time. The overloading is also determined at compile-time - so by the time you actually know the concrete type to use, it's too late.
I don't see that you'd actually be duplicating any logic by using delegates. Alternatively, if you do it with reflection, you can build delegates very easily using Delegate.CreateDelegate - you'll only get a performance hit once, and after that it'll be very fast. See my blog entry about Delegate.CreateDelegate for more information.
I think I'd decide to use a hand-built dictionary or one built with reflection based on how many methods I had and how often they change. You'll probably find KeyedByTypeCollection useful for the dictionary.
Upvotes: 5
Reputation: 103495
Well, the "correct" answer is that Handle() should be a method in ICommand, so that instead of Handle(command)
, you'd be saying command.Handle()
.
Upvotes: 9
Reputation: 29401
You can't, and why would you want to?
That's the whole reason we have polymorphism. If you want to have custom behaviour that is specific to certain types, then the behaviour should live in the type itself and be invoked via a function declared in the base class type.
Upvotes: 2