On C# dynamic and calling base type’s methods

The dynamic keyword has been part of the C# language for quite a while now. I thought I know it well, yet I stumbled upon an interesting case that surprised me.

The code that works

Here’s a piece of code that I started with. This code works like you would expect.

public interface ICanQuack
{
    void Fly<T>(T map);
    void Quack();
}

public class Duck : ICanQuack
{
    public void Fly<T>(T map)
    {
        Console.WriteLine("Flying using a {0} map ({1})", typeof (T).Name, map);
    }

    public void Quack()
    {
        Console.WriteLine("Quack Quack!");
    }
}

class Program
{
    private static ICanQuack quack;
    private static void Main(string[] args)
    {
        SetUpQuack();

        var map = GetMap();

        quack.Fly((dynamic)map);

        Console.ReadKey(true);
    }

    private static void SetUpQuack()
    {
        quack = new Duck();
    }

    private static object GetMap()
    {
        return "a map";
    }
}

Notice the use of dynamic to resolve the generic method type parameter at runtime. This code works and, as you probably guessed, prints:

Flying using a String map (a map)

The innocent change that broke it

Now, even though it’s a completely made up example instead of the real code, flying is something not just ducks do, so let’s extract an interface ICanFly

public interface ICanFly
{
    void Fly<T>(T map);
}

public interface ICanQuack : ICanFly
{
    void Quack();
}

Rest of the code stays the same.

Looks innocent enough right? Except it just broke out code. It we run it now we’ll get the following error
Error

What happened

Well, to be honest, I’m not quite sure I have a good explanation for the behaviour. Like I said, I was surprised myself that this code stops working now. When you use the dynamic keyword C# compiler tries to use all the information it has at compile time, to optimise the code it generates to support the dynamic invocation, so that it has less work to do at runtime. In this case, by definition, everything that implements ICanQuack also implements ICanFly but the binder seems to not bother checking the base interface. I’m sure Jon Skeet has a perfectly good explanation for it.

How to fix it

The exception message points us pretty clearly towards the problem – the runtime binder uses the static type information about ICanQuack to find the Fly method. Since the method is defined on the ICanFly interface, we need to give the binder a hint that ICanFly is where it should look.

To do that, we need to change the following code

quack.Fly((dynamic)map);

into a bit uglier (but working!):

((ICanFly)quack).Fly((dynamic)map);