The following code throws "Ambiguous invocation match" at compile time:
class ABC{}
class DEF{}
class Program
{
static void Main(string[] args)
{
Debug.WriteLine(func(null));
}
static string func(ABC abc)
{
return "";
}
static string func(DEF def)
{
return "";
}
}
But the following code compiles and runs fine:
static void Main(string[] args)
{
Debug.WriteLine(func(null));
}
static string func(int? abc)
{
return "function a";
}
static string func(float? def)
{
return "function b";
}
Outputting
function a
How does C# know what which function to pick in the second example?
When the compiler performs overload resolution on a function call like this it chooses the better function member among the candidates, if one exists. The definition of better function member includes this passage in §7.5.3.2 of the C# language spec:
7.5.3.2 Better function member
[...]
Given an argument list A with a set of argument expressions { E1, E2, ..., EN } and two applicable function members MP and MQ with parameter types { P1, P2, ..., PN } and { Q1, Q2, ..., QN }, MP is defined to be a better function member than MQ if
- for each argument, the implicit conversion from EX to QX is not better than the implicit conversion from EX to PX, and
- for at least one argument, the conversion from EX to PX is better than the conversion from EX to QX.
[...]
In this case, MP
is the first method (P1
being int?
) and MQ
is the second method (Q1
being float?
). So the behavior is easily explained if we can prove that the conversion from null
to int?
is better than the conversion to float?
.
This is determined by the rules in §7.5.3.5:
7.5.3.5 Better conversion target
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
- An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
Since an implicit conversion from int
to float
exists but one from float
to int
does not (reference), int
is the better conversion target when choosing between the two types.
In your example we are dealing with the nullable versions of these types, but the same logic applies because of
6.1.4 Implicit nullable conversions
Predefined implicit conversions that operate on non-nullable value types can also be used with nullable forms of those types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With