First example: null argument
In the first case it will call the string
overload. null
matches both object
and string
, but string is the more specific/derived type. Thus it chooses string
.
Check Eric Lippert's post How does the method overload resolution system decide which method to call when a null value is passed? for a longer explanation for this part of overload resolution.
Now we must determine the best of the applicable candidates. The bestness rules are complicated, but the short version is that more specific is better than less specific.
Second example: integer literal
In the second case it'll choose the first overload, because the literal 7
is int
. If you had used 7u
it would have been uint
and thus the second overload would be preferred.
Integer literals have a well defined type(even if they allow more implicit conversions than normal integral values). You can use suffixes like u
for unsigned, or l
for long to influence that type. Or you can add an explicit cast.
While normally an int
wouldn't be implicitly convertible to uint
, this is an integer constant which is in the valid range of uint
, and the C# compiler has an extra rule to allow implicit conversions between integer constants, provided the constant fits the target's range.
One again Eric explains the details: Why does this implicit conversion from int to uint work?
A constant expression of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type. A constant expression of type long can be converted to type ulong, provided the value of the constant expression is not negative.
In both examples one overload is clearly the best, as far as the C# compiler is concerned, and thus you don't get an ambiguous overloading error.
Personally I think that the first example should give a warning, but either the C# team disagrees, or they simply didn't have time to add that heuristic.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…