.NET Tips and Tricks

Blog archive

Picking Overloaded Methods at Runtime (Multiple Dispatch)

I don't spend a lot of time interacting with dynamic languages like Python, but I think that I've finally found a use for the dynamic keyword in C#. It's something that C++ developers call "multiple dispatch" (or so I'm told).

Normally, if you call a method that that has two overloaded versions, the choice between the two overloads is made at compile time, based on how the parameters passed to the method are declared. But, by using the dynamic keyword, you can defer the choice between the two methods until run time and have the choice based on the datatype of the data in the parameters, instead of on the way the parameters are declared.

For instance, assume two classes: one called BaseCustomer and another called PremiumCustomer that inherits from BaseCustomer. Also assume a method with two overloaded versions: one version that accepts a Customer object and one that accepts a PremiumCustomer object. Here are the two methods:

public void ProcessCustomer(Customer cust)
{
}

public void ProcessCustomer(PremiumCustomer cust)
{
}

Now, here's some code that calls the two versions of the ProcessCustomer method. Guess which version is called each time:

Customer cst = new Customer();
ProcessCustomer(cst);
PremiumCustomer pcst = new PremiumCustomer();
ProcessCustomer(pcst);

You probably guessed that the first two lines of code will call the first version of the ProcessCustomer method -- the one that accepts a Customer object parameter. After all, the cst variable passed to the method is declared as Customer and is referencing a Customer object. And, just as probably, you guessed that the second two lines of code will call the second version of the method that accepts a PremiumCustomer. You'd be right both times.

But how about the following example, which declares the variable passed to the ProcessCustomer method as Customer, but holds a reference to a PremiumCustomer? What's your guess for this code:

Customer cst = new PremiumCustomer();
ProcessCustomer(cst);

If you guessed that this example still calls the first version of the ProcessCustomer method, you'd be right. That's because the decision on which overloaded version to call is made at compile time, based on the datatype of the variable being passed (and the cst variable is declared as Customer).

You might prefer, however, to have the decision made at run time based on the datatype of the object actually being passed. In other words, in that last set of code you might prefer to have the second version of the ProcessCustomer method called because the cst variable is referencing a PremiumCustomer object. You can do that by casting the parameter using the dynamic keyword, as in this example:

Customer cst = new PremiumCustomer();
ProcessCustomer((dynamic) cst);

This code will call the second version of the ProcessCustomer method because, even though the cst parameter is still declared as Customer, the variable is pointing at a PremiumCustomer object. I won't always want that behavior, but there will be times when this technique is going to be very useful.

Posted by Peter Vogel on 01/10/2013 at 1:16 PM


comments powered by Disqus

Reader Comments:

Tue, Feb 5, 2013 Mark Johnson

Where is the dynamic keyword used?

Wed, Jan 23, 2013 Peter Vogel Canada

BDM: I did some very rough testing and I found that using the dynamic keyword seemed to make the call take longer than omitting it (we're taking milliseconds here)--but I wasn't getting the behavior I wanted (i.e. the overloaded method was being selected based on the variable type). To get the behavior I wanted, I left out the dynamic keyword but added in some tests and upcasting code (as you mention). That code seemed to take longer than using the dynamic keyword (still talking milliseconds here). But I have to admit that I didn't spend a lot of time on those tests: for me, the real benefit of this tip is that if I add a new overloaded method or a new class, I don't have to go back and update the upcasting code: it will do the right thing. My maintenance costs are lowered and I like that very much. So when I was testing, I just wanted to make sure that using the dynamic keyword wasn't going to be a performance hog. There's another issue: because this is being handled by the compiler, there's no guarantee that the performance you get with this version of .NET will be the performance you get in the next version: how the compiler handles this is an "implementation detail" that will vary from one version to another. Having said that, using the dynamic keyword will, if anything, probably get faster over time...probably. Sorry I can't be more help.

Wed, Jan 23, 2013 BDM

Peter, do you have any info as far as overhead is concerned? Using your example, I have code in one place that actually has to check if(cst is PremiumCustomer)then cast "up" before calling. This would solve it, but my code is in a place that needs high performance and I don't dare change it without knowing any side-effects. Thanks!

Fri, Jan 11, 2013 Peter Vogel Canada

Sunil: I think that's a very good question--and let me be clear that I do think that this is a niche solution that you'll only need occasionally. I'm assuming that the program has a variable of type Customer that's pointing at an object of type PremiumCustomer (that's OK because PremiumCustomer inherits from Customer). The program then calls ProcessCustomer, invoking one of the two versions of the method. By using the 'dynamic' keyword the method that gets invoked is decided by the type of the object being passed, not by the way the variable pointing to the object is declared. In this example, the object will be passed to the version of the method that expects a PremiumCustomer object (and, therefore, a method that uses the PremiumCustomer's "extra" methods attributes); Without the 'dynamic' keyword, the object will be passed to the method based on the variable type--the version expecting a Customer object (and, therefore, a method that will ignore the PremiumCustomer's "extra" methods and attributes). So, using this method, the object ends up in a version of ProcessCustomer that can use the PremiumCustomer's extra methods and properties. You're right in that the program with the variable declared as Customer can't use the "extra" methods and attributes but, with the 'dynamic' keyword, the method being called will be able to. Is that any help?

Fri, Jan 11, 2013 Sunil Ciszewski United States

When would you want to do that? If the variable is of type Customer, not PremiumCustomer, wouldn't it be missing certain methods and attributes expected on a PremiumCustomer. Likely the ProcessCustomer for the PremiumCustomer operates on those, so why would you do this? Just asking.

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.