I just discovered this interesting issue:
int done = 50;
int? total = 100;
var perc = done * 100 / total; // No problem
// Error: Argument 2: cannot convert from 'int?' to 'byte'
// Argument 1 is still int32
var perc2 = Math.Min(100, done * 100 / total);
At first, my code only needed the first perc
. Surprisingly there was no error there as I missed a null
check that should be there. I didn't see my mistake until later:
Then there are some cases where the estimate total
is more less than what it should be but the percent needs to be capped at 100 so I added the Math.Min
. Now I discovered I missed a null check and the error message is kind of misleading.
What is happening here? What is C# attempting to do in this case?
When you call a method in code, the compiler will try to find that method provided the argument list you pass (if any). Take this method:
public static void M(int i) { }
You can call it using M(42)
and all is well. When there are multiple candidates:
public static void M(byte b) { }
public static void M(int i) { }
The compiler will apply "overload resolution" to determine "applicable function members", and when more than one, the compiler will calculate the "betterness" of the overloads to determine the "better function member" that you intend to call.
In the case of the above example, M(42)
, the int
overload is chosen because non-suffixed numeric literals in C# default to int
, so M(int)
is the "better" overload.
(All parts in "quotes" can be looked up in the C# language specification, 12.6.4 Overload resolution.)
Now onto your code.
Given the literal 100
could be stored in both a byte
and an int
(and then some), and your second argument doesn't match either overload, the compiler doesn't know which overload you intend to call.
It has to pick any to present you with an error message. In this case it appears to pick the first one in declaration order.
Given this code:
public static void Main()
{
int? i = null;
M(100, i);
}
public static void M(int i, int i2) {}
public static void M(byte b, byte b2) {}
It mentions:
cannot convert from 'int?' to 'int'
If we swap the method declarations:
public static void M(byte b, byte b2) {}
public static void M(int i, int i2) {}
It complains:
cannot convert from 'int?' to 'byte'