Multimethods in C# 4.0 with 'dynamic'

(Continuing from the post on implementing the Visitor pattern in C# 4.0)

A virtual method is polymorphic in one dimension (the runtime class of the object the method is attached to). Multimethods (multiple dispatch) are polymorphic in multiple dimensions, which can be very useful in some cases. The dynamic keyword in C# 4.0 allows for method selection that depends on the runtime class of the arguments, not just the attached object. This allows true multimethods. (Of course the lookup rules for dynamic are complex so extremely complex cases might not resolve the way you want).

The basic idea is to create method overloads which take all the (subclass1, subclass2) combinations that you are interested in and then have the (superclass, superclass) method cast its arguments to dynamic and then call the method again and let runtime resolution do its thing. In the spirit of the Wikipedia article on multimethods, here is a spaceship/asteroid collision example:

 (code edited to separate the names of the methods)

using System;

namespace MultiMethods
{
    class Program
    {
        class Thing { }
        class Asteroid : Thing { }
        class Spaceship : Thing { }

        static void CollideWithImpl(Asteroid x, Asteroid y)
        {
            Console.WriteLine("Asteroid hits an Asteroid");
        }

        static void CollideWithImpl(Asteroid x, Spaceship y)
        {
            Console.WriteLine("Asteroid hits a Spaceship");
        }

        static void CollideWithImpl(Spaceship x, Asteroid y)
        {
            Console.WriteLine("Spaceship hits an Asteroid");
        }

        static void CollideWithImpl(Spaceship x, Spaceship y)
        {
            Console.WriteLine("Spaceship hits a Spaceship");
        }

        static void CollideWith(Thing x, Thing y)
        {
            dynamic a = x;
            dynamic b = y;
            CollideWithImpl(a, b);
        }

        static void Main(string[] args)
        {
            var asteroid = new Asteroid();
            var spaceship = new Spaceship();
            CollideWith(asteroid, spaceship);
            CollideWith(spaceship, spaceship);
        }
    }
}