Overloading
Just
as a reminder, overloading is what happens when you have two methods with the same name
but different signatures. At compile time, the compiler works out which one
it's going to call, based on the compile time types of the arguments and the
target of the method call.
Now,
things can get a little bit confusing sometimes when it comes to resolving
overloads... especially as things can change between versions. This article
will point out some of the things you might run into... but I'm not going to claim
it's an authoritative guide to how overloading is performed. For that, read the
specification - but be aware that you may get lost in a fairly complex topic.
Overloading interacts with things like type inference and implicit conversions
(including lambda expressions, anonymous methods and method groups, all of
which can become tricky). All specification references are from the C# 4 specification.
This article is also not going to go into the
design choices of when it's appropriate and when it's not. I'll give a little
advice about when it might be potentially very confusing to use overloading,
but anything beyond that will have to wait for another time. I will say that in general I believe overloading
should be used for convenience, usually with all overloads ending up calling
one "master" method. That's not always the case, but I believe it's
the most common scenario which is appropriate.
In each example, I'll give a short program which
will declare some methods and call one - and then I'll explain what gets called
in which version of C#, and why. As I'm not trying to focus on the design
decisions but merely the mechanical choices the C# compiler makes, I haven't
tried to make the examples do anything realistic, or even given them realistic
names: the overloaded method is always Foo, and it will always just print its own
signature. Of course the action taken is irrelevant, but it makes it easier to
grab the code and experiment with it if you want to.
Simple cases
Using System;
Class Test
{
Static
void Foo(int x)
{
Console.WriteLine("Foo(int x)");
}
Static
void Foo(string y)
{
Console.WriteLine("Foo(string y)");
}
Static
void Main()
{
Foo ("text");
}
}
using System;
class Test
{
static
void Foo(int x)
{
Console.WriteLine("Foo(int x)");
}
static
void Foo(double y)
{
Console.WriteLine("Foo(double y)");
}
static void Main()
{
Foo
(10);
}
This time, Foo(int x) will be printed. Both
methods are applicable - if we removed the method taking an `int`, the method
taking a `double` would be called instead. The compiler decides which one to pick
based on the better function member rules (section 7.5.3.2) which look at
(amongst other things) what conversions are involved in going from each
argument to the corresponding parameter type (int for the first method, double
for the second). There are more rules (section 7.5.3.3) to say which conversion
is better than the other - in this case, a conversion from an expression of
type int to int is better than a conversion from int to double, so the first
method "wins".
Multiple
parameters
When there are multiple parameters involved, for
one method to "beat" another one it has to be at least as good for
each parameter, and better for at least one parameter. This is done on a
method-by-method comparison: a method doesn't have to be better than all other
methods for any single parameter. For example:
Difference between overloading and overriding |
using System;
class Test
{
static
void Foo(int x, int y)
{
Console.WriteLine("Foo(int x, int y)");
}
static
void Foo(int x, double y)
{
Console.WriteLine("Foo(int x, double y)");
}
static
void Foo(double x, int y)
{
Console.WriteLine("Foo(double x, int y)");
}
static
void Main()
{
Foo(5, 10);
}
No comments:
Post a Comment