C#: Passing null to overloaded method - which method is called?
-
23-08-2019 - |
Question
Say I have two overloaded versions of a C# method:
void Method( TypeA a ) { }
void Method( TypeB b ) { }
I call the method with:
Method( null );
Which overload of the method is called? What can I do to ensure that a particular overload is called?
Solution
It depends on TypeA
and TypeB
.
- If exactly one of them is applicable (e.g. there is no conversion from
null
toTypeB
because it's a value type butTypeA
is a reference type) then the call will be made to the applicable one. - Otherwise it depends on the relationship between
TypeA
andTypeB
.- If there is an implicit conversion from
TypeA
toTypeB
but no implicit conversion fromTypeB
toTypeA
then the overload usingTypeA
will be used. - If there is an implicit conversion from
TypeB
toTypeA
but no implicit conversion fromTypeA
toTypeB
then the overload usingTypeB
will be used. - Otherwise, the call is ambiguous and will fail to compile.
- If there is an implicit conversion from
See section 7.4.3.4 of the C# 3.0 spec for the detailed rules.
Here's an example of it not being ambiguous. Here TypeB
derives from TypeA
, which means there's an implicit conversion from TypeB
to TypeA
, but not vice versa. Thus the overload using TypeB
is used:
using System;
class TypeA {}
class TypeB : TypeA {}
class Program
{
static void Foo(TypeA x)
{
Console.WriteLine("Foo(TypeA)");
}
static void Foo(TypeB x)
{
Console.WriteLine("Foo(TypeB)");
}
static void Main()
{
Foo(null); // Prints Foo(TypeB)
}
}
In general, even in the face of an otherwise-ambiguous call, to ensure that a particular overload is used, just cast:
Foo((TypeA) null);
or
Foo((TypeB) null);
Note that if this involves inheritance in the declaring classes (i.e. one class is overloading a method declared by its base class) you're into a whole other problem, and you need to cast the target of the method rather than the argument.
OTHER TIPS
Jon Skeet has given a comprehensive answer, but from a design point of view you shouldn't depend on corner-cases of the compiler specification. If nothing else, if you have to look up what it does before you write it, the next person to try to read it won't know what it does either. It's not maintainable.
Overloads are there for convenience, and two different overloads with the same name should do the same thing. If the two methods do different things, rename one or both of them.
It's more usual for an overloaded method to have variants with varying numbers of parameters, and for the overload with less parameters to supply sensible defaults.
e.g. string ToString(string format, System.IFormatProvider provider)
has the most parameters,
string ToString(System.IFormatProvider provider)
supplies a default format, and
string ToString()
supplies a default format and provider,
Jon Skeet already answered which overload gets chosen by default, but if you want to ensure that particular overload is called, it is often better to use named parameters than cast.
If you have:
void Method( TypeA a ) { }
void Method( TypeB b ) { }
You can call Method(a: null);
or Method(b: null);
ambigous call. (compile time error).
A simple solution is to create another method with the signature of:
void Method() { }
or better to update the signature on one of the methods to be:
void Method( TypeB b = null ) { }
and then call it as so:
Method();
At compile time the value null
is untyped and so the compiler can't match it up with one of the method signatures. At run time any variable that might resolve to null
will still be typed and so it won't cause a problem.
Just type cast it to what you want the overloaded value to be
void method(int);
void method(string);
method((string) null){};
This will call the