.NET Zone is brought to you in partnership with:

I'm a software developer working as a senior consultant at Kentor in Stockholm, Sweden. My core competence is as a technical specialist within development and system architecture. In my heart I am, and probably will remain, a programmer. I still think programming is tremendously fun, more than 20 years after I first tried it. That's why my blog is named Passion for Coding.  Anders is a DZone MVB and is not an employee of DZone and has posted 81 posts at DZone. You can read more from them at their website. View Full User Profile

Dynamic Overload Resolution

04.10.2012
| 2933 views |
  • submit to reddit

Both when coding in C++ and C# I’ve had problems with overload resolution being static. There are workarounds, for example the visitor pattern but it requires quite an effort to implement. More importantly it cannot be implemented without changing the visited element. With C#4′s dynamic keyword there is finally a better solution.

To illustrate the problem I’ll implement the ITransportationService interface.

public interface ITransportationService
{
    void TransportAnimal(Animal a);
}

I’ll implement it by delegating the transportation work to the AnimalTransport class. The problem is that AnimalTransport has a special overload for elephants and the ITransportationService.TransportAnimal interface doesn’t.

A Simple Transport

First I’ll show a simple transport, which makes use of the AnimalTransport class.

public static class AnimalTransport
{
    public static void LoadAnimal(Animal animal)
    {
        Debug.WriteLine("Putting " + animal.Name + " in a cage.");
    }
 
    public static void LoadAnimal(Elephant elephant)
    {
        Debug.WriteLine("Loading " + elephant.Name + " on a trailer.");
    }
}
 
public class SimpleTransportation : ITransportationService
{
    public void TransportAnimal(Animal a)
    {
        AnimalTransport.LoadAnimal(a);
    }
}

Executing the code shows a problem.

Transporting an elephant with SimpleTransportation...
Putting Hanibal in a cage.

I think that it might be a problem trying to put Hanibal into an ordinary size pet cage.

A Flexible Transport with Dynamic

Introducing the dynamic keyword handles the situation.

public class FlexibleTransportation : ITransportationService
{
    public void TransportAnimal(Animal a)
    {
        AnimalTransport.LoadAnimal((dynamic)a);
    }
}

Executing the code now loads Hanibal on a trailer instead.

Transporting an elephant with FlexibleTransportation...
Loading Hanibal on a trailer.
Objectoriented Principles

Objectorientation is all about separation of concerns and encapsulation of behaviour. In most cases, it is appropriate to defer to the class itself to decide behaviour that depends on the runtime type. For example, a RunDistance method on the Animal class would be an ordinary virtual (and probably abstract) method, letting each concrete implementation return how fast the specific animal runs.

In this case however I don’t think that it is appropriate. The animal itself should be completely ignorant about how it is transported.
Looking at the AnimalTransport class I think that it is completely reasonable to have a special overload for the elephant. It is huge and requires special handling compared to ordinary animals like cats and dogs.

It is also totally appropriate that the ITransportation interface knows very little about the details of the Animal class hierarchy. Adding a separate overload (if we are at all allowed to change it) there for the elephant would reveal details at the wrong place.
As I mentioned in the beginning of the post the visitor pattern can solve the problem. Unfortunately that requires that the Animal class hierarchy has support for visitors, which is probably not the case if it comes from a library.

I think that using dynamic in this case makes the code clean, elegant and still type safe. If all other classes are already existing and not possible to change, the only other alternative would be manually check the type during runtime.

Published at DZone with permission of Anders Abel, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)