Dynamic Dispatch in C#
Today, I’d like to describe one of the useful concepts from dynamic languages called dynamic dispatch and I’d like to show you multiple ways how you can implement it in C#.
Firstly, there is a lot of ambiguity and confusion about terms like dispatch, binding and typing, so I think makes sense to go through what dispatch actually means. In simple words, it is a way how the programming language calls a method or a function. In general, it doesn’t matter whether the method belongs to an instance or to a class.
There are two types of dispatch, static and dynamic. The first one means that every method is known at the compile time. Dynamically dispatched methods are determined at run time based on its parameter’s types. And here, imaging that when you call x.ToString() you should imagine x as a parameter.
Also, dynamically dispatched languages could be divided in two groups – single and multiple dispatched. Single ones use just one parameter to select a method. On the other hand, the multiple ones can take advantage of as many parameters they want.
There is a lot of languages that are single dispatched and C# was one of them until the version 4.0. Usually, this kind of dispatch is implemented by inheritance model with virtual methods. You inherit from a parent class, override a method and it gets called in runtime based on the current object’s type.
But is there any other mechanism that you could use in C# for dynamic dispatch?
Let’s assume that we have couple classes in a simple object hierarchy and we can’t add a code to them for whatever reason (like we don’t own the code or it doesn’t belong there).
public interface IBar {}
public class Bar : IBar {}
public sealed class FooBar : Bar {}
// Simple helper for demonstration
public static class ConsolePrinter
{
public static void Print(IBar item)
{
Console.WriteLine("IBar");
}
public static void Print(Bar item)
{
Console.WriteLine("Bar");
}
public static void Print(FooBar item)
{
Console.WriteLine("FooBar");
}
}
For each type we want to call a different method based on the object’s runtime type.
var bar = new Bar();
var foo = new FooBar();
IBar ibar = new FooBar();
ConsolePrinter.Print(bar);
ConsolePrinter.Print(foo);
ConsolePrinter.Print(ibar);
// prints Bar
// prints FooBar
// prints IBar
In the code above, static dispatch makes sure that for each call a method with the appropriate signature is called. This is fine for bar and foo objects, but for ibar the method with interface signature is called instead of the one with the object’s true type FooBar.
And things get worst when you put those objects into an array.
IBar[] items = { bar, foo, ibar };
foreach (var item in items)
{
ConsolePrinter.Print(item);
}
// prints IBar
// prints IBar
// prints IBar
These examples are a bit artificial, but imagine that you have a property on the class that contains array of IBars or they are served as an input to a method.
We wanted the output to be Bar, FooBar and FooBar and the static dispatch doesn’t work here. What can we do with that?
Dynamic keyword
The dynamic keyword was introduced in C# 4.0 for simplifying interactions with COM objects and CLR dynamic languages like IronPython and IronRuby. Also, it is used in ASP.NET MVC projects for passing views and interacting with them in Razor templates.
This keyword brings true multiple dynamic dispatch to C# giving it even greater expression power. Let’s change the example above and cast every item to dynamic object.
foreach (dynamic item in items)
{
ConsolePrinter.Print(item);
}
// prints Bar
// prints FooBar
// prints FooBar
A simple change and from statically dispatched piece of code we have a dynamic one. But bear in mind that with power there comes responsibility, and you should know when to use it.
The drawback of using this keyword is extending your working set and therefore hurting performance. Also, it was designed for other purposes, so use it only for a huge simplification of your code.
Personally, I would recommend using dynamic keyword in parsers, utilities, tests and all the cases it was designed for.
Dictionary
Apart from the dynamic keyword, there is a way to achieve this behavior with a simple dictionary.
var actions = new Dictionary<Type, Action<IBar>>
{
{typeof (IBar), ConsolePrinter.Print},
{typeof (Bar), i => ConsolePrinter.Print((Bar)i)},
{typeof (FooBar), i => ConsolePrinter.Print((FooBar)i)}
};
foreach (var item in items)
{
actions[item.GetType()](item);
}
It’s probably better than having lots of if statements, but it could be considered as an anti-pattern. Don’t let your dictionary grow too much or you are going to end up in refactoring hell.
But unlike with the visitor pattern that comes next, you don’t have to modify your types to make it work and it is available in earlier versions of C# where you don’t have the dynamic keyword.
Visitor
The classic approach of solving dynamic dispatch problem would be using a visitor pattern. However, you need to modify your types a little and create a new class and an interface.
public interface IBar
{
void Accept(IBarVisitor visitor);
}
public sealed class FooBar : Bar
{
public override void Accept(IBarVisitor visitor)
{
visitor.Visit(this);
}
}
public class Bar : IBar
{
public virtual void Accept(IBarVisitor visitor)
{
visitor.Visit(this);
}
}
public interface IBarVisitor
{
void Visit(FooBar item);
void Visit(Bar item);
}
public sealed class PrintBarVisitor : IBarVisitor
{
public void Visit(FooBar item)
{
ConsolePrinter.Print(item);
}
public void Visit(Bar item)
{
ConsolePrinter.Print(item);
}
}
Be careful to make the Visit method virtual and make sure you override it in all descendants. Otherwise it won’t work.
The usage of this pattern looks like this.
var visitor = new PrintBarVisitor();
foreach (var item in items)
{
item.Accept(visitor);
}
As I already said, you have to modify your types and there are situations where you don’t want to or you can’t. Also, it’s a lot of code for a simple thing and it gets much more messy when you need support for multiple dispatch. Then the code size grows exponentially.
The good thing about visitor is that it is a very modular pattern and it fits your needs when you want to have different functionalities encapsulated in more visitors.
To sum it up, C# offers many options to deal with dynamic dispatch. It has powers of fully dynamic languages and you can choose the best solutions.
Comments
Musa Alp: What is the difference, if we change var instead of dynamic?
Jakub: Using var is just a shortcut for you to get statically inferred type in from the compiler. So it is not inferred at run time like dynamic would be.
The example above with the foreach mentions the difference. At that point, the best compiler can do is it can infer the IBar interface. i cant imagine, is it affect the result