C#: Passing null to overloaded method - which method is called?
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.
Passing null value to overloading method where Object and String as param in C#
The C# compiler takes the most specific overload possible.
As string
is an object
, and it can have the value of null
, the compiler deems string
to be more specific.
Method overloading and null value
It is a product of overload resolution. Your argument, null
, is convertible to both object
and int[]
. The compiler therefore picks the most specific version, because int[]
is more specific than object
.
Overloading null ambiguity
The problem is that both string
and object
are nullable, so null
could refer to either overload of the method. You have to cast the null value—as stupid as that sounds—to say explicitely which overload you want to call.
method("string", (string) null);
method("string", (object) null);
This is basically the same as if you defined a variable of either type and passed that then:
string param1 = null;
object param2 = null;
method("string", param1); // will call the string overload
method("string", param2); // will call the object overload
Both param1
and param2
have the same value, null
, but the variables are of different types which is why the compiler is able to tell exactly which overload it needs to use. The solution above with the explicit cast is just the same; it annotates a type to the null
value which is then used to infer the correct overload—just without having to declare a variable.
Different overload method is chosen, depending from where it's called with a null parameter
Which overload to call (binding) is statically fixed for each invocation expression at compile-time (unless you use type dynamic
at compile-time). Just because the expression you use for argument happens to evaluate to another type when the program runs, the overload will not magically change.
Examples:
FormatStuff.Format(null);
The compile-time type does not exist (null), but since there is an implicit conversion from the null
literal to object
and an implicit conversion from null
to IEnumerable<object>
as well, both overloads are candidates. In that case the overload with IEnumerable<object>
is preferred because it is more specific.
FormatStuff.Format((object)null);
In this case the compile-time type of the expression is object
, so only one overload applies, and that is used.
IEnumerable<int> intnumerable
// ...
FormatStuff.Format(intnumerable);
In the above case the compile-time type of what you pass is IEnumerable<int>
. Here int
is a value-type. An IEnumerable<int>
is not an IEnumerable<object>
at compile-time. This is fixed at compile-time; it does not matter whether intnumerable
happens to be null
at run-time, and if non-null, it does not matter what the actual type (some concrete class or struct implementing IEnumerable<int>
) is at run-time.
IEnumerable<string> strEnumerable
// ...
FormatStuff.Format(strEnumerable);
Finally, in this case, since string
is a reference type, the compile-time covariance of IEnumerable<out T>
applies. So an IEnumerable<string>
is an IEnumerable<object>
. Therefore both overloads apply, and the most specific one is preferred.
CLR question. Why method overloading in C# decides that null is a string?
The answer is because it must choose a reference type (null doesn't work for value types), and every string
is an object
, but not every object
is a string
. See Jon Skeet's answer to this question for more information.
In response to your second example, if a variable that is null is passed to is
, it will always evaluate to false, no matter what.
C# pass a null value as a generic object rather than a type for overloaded methods
You can force the behavior by casting null
to anything other than LegacyData
.
var x = new Test();
x.PerformCheck((object)null);
public class Test
{
public void PerformCheck(LegacyData data) { Console.WriteLine("legacy"); }
public void PerformCheck(object data) { Console.WriteLine("other"); }
}
public class LegacyData {}
This outputs "other" as expected.
How to overload Null-conditional operators ?.
No, you can't overload the Null-conditional operators. See the list of C# Overloadable operators.
Addendum The ability to overload this operator has actually been proposed to the C# language team. See Proposal: Allow null conditional (?.) and null coalescing ()?? operators to be overloaded and Proposal: nullable-like types. These has not been aproved.
What follows is my understanding of the concerns regarding these and similar proposals:
Changing the semantics of these operators could have a lot of ramifications. For example, given that the operators are static, it would be possible to make it say that something that is null
is not. Which would mean a lot of problems for a lot of code. On the flip side, you could have code that hangs too long on a reference or not long enough that would bring problems with the garbage collection.
Even if these and similar issues could be solved, it is not a change to be taken lightly. We are talking about a lot of problems for existing code, that is already deployed in production.
Related Topics
Read and Write File on Streamingassetspath
How to Install Android APK from Code in Unity
How Does Wcf Deserialization Instantiate Objects Without Calling a Constructor
How to Make Smtp Authenticated in C#
Simple iOS Bluetooth Data Transmission Using Unity
What Is a Dynamic Language, and Why Doesn't C# Qualify
ASP.NET Page Is Not Loading CSS Styles
Can a Web User Control (.Ascx) Use a CSS File for Styling
C# Sha-1 VS. PHP Sha-1...Different Results
What Is the Purpose of Anonymous { } Blocks in C Style Languages
HTML Table (Text) to Image Using C#
Using C# to Dynamically Generate CSS Files
How to Get the HTML Output of a Usercontrol in .Net (C#)
Iterate Multi-Dimensional Array with Nested Foreach Statement
Sometimes Adding a Wcf Service Reference Generates an Empty Reference.Cs