C sharp - Multiple Dispatch using dynamic in C#
1. What is Multiple Dispatch?
In most object-oriented languages (including C# by default), method selection is based on the compile-time type of the reference.
This is called single dispatch.
Multiple dispatch means:
Method selection depends on the runtime types of multiple arguments, not just one.
C# does not natively support full multiple dispatch like some other languages, but it can simulate it using the dynamic keyword.
2. Single Dispatch in C#
Example:
class Animal { }
class Dog : Animal { }
class Program
{
static void Speak(Animal a)
{
Console.WriteLine("Animal sound");
}
static void Speak(Dog d)
{
Console.WriteLine("Bark");
}
static void Main()
{
Animal a = new Dog();
Speak(a);
}
}
Output:
Animal sound
Why?
Because method overload resolution happens at compile time based on declared type (Animal), not runtime type (Dog).
3. Using dynamic for Runtime Dispatch
Now change:
static void Main()
{
dynamic a = new Dog();
Speak(a);
}
Output:
Bark
Now:
-
Method resolution happens at runtime
-
Actual object type (
Dog) is used
This simulates multiple dispatch behavior.
4. What is dynamic?
dynamic tells the compiler:
Skip compile-time type checking for this variable.
Resolve everything at runtime.
Internally:
-
C# uses the Dynamic Language Runtime (DLR)
-
Method binding happens during execution
5. Multiple Dispatch with Two Parameters
Example:
class Shape { }
class Circle : Shape { }
class Rectangle : Shape { }
class Program
{
static void Interact(Circle c, Rectangle r)
{
Console.WriteLine("Circle interacts with Rectangle");
}
static void Interact(Shape s1, Shape s2)
{
Console.WriteLine("Generic interaction");
}
static void Main()
{
dynamic c = new Circle();
dynamic r = new Rectangle();
Interact(c, r);
}
}
Output:
Circle interacts with Rectangle
Here:
-
Both parameters are resolved at runtime
-
Closest matching overload is selected
This resembles true multiple dispatch.
6. When is dynamic Useful?
-
Interoperability with dynamic languages (Python, JavaScript)
-
COM interop
-
Reflection simplification
-
JSON handling
-
Runtime plugin systems
Example:
dynamic obj = GetUnknownObject();
obj.SomeMethod();
No casting required.
7. Performance Consideration
Using dynamic:
-
Slower than static typing
-
Requires runtime binder
-
Cannot be inlined by JIT
-
Loses compile-time safety
Therefore:
Use only when necessary.
8. Differences: object vs dynamic
| object | dynamic |
|---|---|
| Checked at compile time | Checked at runtime |
| Requires casting | No casting required |
| Safe | Less safe |
| Better performance | Slower |
Example:
object obj = "Hello";
obj.Length; // Compile error
With dynamic:
dynamic obj = "Hello";
Console.WriteLine(obj.Length); // Works
9. Risk of Runtime Errors
Since type checking is skipped:
dynamic x = 5;
x.NonExistentMethod();
This compiles successfully but crashes at runtime.
So debugging becomes harder.
10. Real-World Example: Visitor Pattern Alternative
Traditional Visitor Pattern is used to simulate multiple dispatch.
Using dynamic, you can simplify visitor logic without complex pattern implementation.
But:
-
It sacrifices type safety
-
Not always recommended for large systems