Question

class Order { ... }

class OrderA : Order { ... }

class OrderB : Order { ... }

class OrderC : Order { ... }

class OrderD : Order { ... }


private Order GetOrder() { ... }

How can i have a method that dynamically casts the returned Order object to any of the specific ones:

private T GetSpecificOrder<T>(T order) : where T : Order
{
    ...
}

And i wanna call it like:

var myOrder = GetOrder();
var specificOrder = GetSpecificOrder<Order>(myOrder);
HandleOrder(specificOrder);

I want that specificOrder object is instantiated as one of the sub classes so i can call it like this:

HandleOrder(OrderA o) { ... }
HandleOrder(OrderB o) { ... }
HandleOrder(OrderC o) { ... }
HandleOrder(OrderD o) { ... }

What am I doing wrong?

Was it helpful?

Solution

It sounds like you're expecting overload resolution to occur at execution time. That doesn't happen... unless you use dynamic, which may well be the simplest solution for you:

dynamic order = GetOrder(orderId);
HandleOrder(order); // The right overload will be picked at execution time

Another alternative would be to use double-dispatch / the visitor pattern, but personally I find that a bit clunky.

Another alternative would be to make a Dictionary<Type, Action<Order>> like this:

private static readonly Dictionary<Type, Action<Order>> orderHandlers = 
    new Dictionary<Type, Action<Order>>
{
    { typeof(OrderA), order => HandleOrder((OrderA) order) },
    { typeof(OrderB), order => HandleOrder((OrderB) order) },
    { typeof(OrderC), order => HandleOrder((OrderC) order) },
    { typeof(OrderD), order => HandleOrder((OrderD) order) },
};

Then just fetch the relevant delegate and call it:

orderHandlers[order.GetType()](order);

OTHER TIPS

You cannot do this with generics: whatever goes into the angle brackets must be a type that is known at compile time, so this line

var specificOrder = GetSpecificOrder<Order>(myOrder);

will require a cast to become OrderA, OrderB, etc.

However, there are at least two ways to work around the situation:

  1. Use the Visitor Pattern by adding an Accept method to the Order and its subclasses, or
  2. By using dynamic, in which case the runtime will perform the correct dispatch for you.

Here is how to implement the #1:

interface IOrderHandler {
    void HandleOrder(OrderA o);
    void HandleOrder(OrderB o);
    void HandleOrder(OrderC o);
    void HandleOrder(OrderD o);
}
abstract class Order { abstract void Accept(IOrderHandler h); }

class OrderA : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }

class OrderB : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }

class OrderC : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }

class OrderD : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }

...

var myOrder = GetOrder();
IOrderHandler handler = ... // Obtain the handler
myOrder.Accept(handler);    // This will call the correct HandleOrder

Here is how to implement the #2:

dynamic myOrder = GetOrder();
HandleOrder(myOrder); // Will dispatch based on the runtime type

Try this...

private T GetSpecificOrder<T>(T order)
    {
     return (T)Convert.ChangeType(T, typeof(T));
    }

You would need to call GetSpecificOrder as the desired derived classed:

var specificOrder = GetSpecificOrder<OrderA>(myOrder);

Or cast it:

var specificOrder = (OrderA)GetSpecificOrder<Order>(myOrder);

And then you can assign whatever properties are unique to the given derived class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top