I've stumbled upon this (in my point of view error) weird behavior, and I would appreciate it if someone could tell me why the compiler behaves like this, or maybe I've got lucky and found a compiler bug ;-)
All is compiled against .net6.0 (using VS 2022)
This is the first version of the code:
internal class Program
{
private static void Main(string[] args)
{
long longValue = 0;
string stringValue = "";
bool boolValue = false;
DateTime dateTimeValue = DateTime.Now;
double doubleValue = 0;
Console.Write("expect long => ");
SetValue(val => longValue = val);
Console.Write("expect string => ");
SetValue(val => stringValue = val);
Console.Write("expect bool => ");
SetValue(val => boolValue = val);
Console.Write("expect DateTime => ");
SetValue(val => dateTimeValue = val);
Console.ReadKey();
}
private static void SetValue(Action<long> setter)
{
Console.WriteLine("long called");
setter(1337);
}
private static void SetValue(Action<string> setter)
{
Console.WriteLine("string called");
setter("foo");
}
private static void SetValue(Action<bool> setter)
{
Console.WriteLine("bool called");
setter(true);
}
private static void SetValue(Action<DateTime> setter)
{
Console.WriteLine("DateTime called");
setter(DateTime.Now.AddDays(10));
}
}
It produces this output:
expect long => long called
expect string => string called
expect bool => bool called
expect DateTime => DateTime called
Now I add a setValue call for doubleValue
Console.Write("expect double => ");
SetValue(val => doubleValue = val);
Here I'm expecting a compiler error complaining there is no suitable overloaded version of SetValue. But instead, it compiles fine and produces this output:
expect long => long called
expect string => string called
expect bool => bool called
expect DateTime => DateTime called
expect double => long called
Notice the last line where we can see that the program has called the wrong setValue version (at this point, there is no "right" setValue version for the double data type).
If I now add a SetValue version that handles doubles:
private static void SetValue(Action<double> setter)
{
Console.WriteLine("double called");
setter(13.37);
}
the compiler complains CS0121 The call is ambiguous between the following methods or properties: 'Program.SetValue(Action<long>)' and 'Program.SetValue(Action<double>)'
I can now make the call unambiguous in several ways. First, as you can see in the final version of the code:
internal class Program
{
private static void Main(string[] args)
{
long longValue = 0;
string stringValue = "";
bool boolValue = false;
DateTime dateTimeValue = DateTime.Now;
double doubleValue = 0;
Console.Write("expect long => ");
SetValue(val => longValue = val);
Console.Write("expect string => ");
SetValue(val => stringValue = val);
Console.Write("expect bool => ");
SetValue(val => boolValue = val);
Console.Write("expect DateTime => ");
SetValue(val => dateTimeValue = val);
Console.Write("expect double => ");
SetValue(new Action<double>(val => doubleValue = val));
Console.Write("expect double => ");
SetValue((double val) => doubleValue = val);
Console.ReadKey();
}
private static void SetValue(Action<long> setter)
{
Console.WriteLine("long called");
setter(1337);
}
private static void SetValue(Action<string> setter)
{
Console.WriteLine("string called");
setter("foo");
}
private static void SetValue(Action<bool> setter)
{
Console.WriteLine("bool called");
setter(true);
}
private static void SetValue(Action<DateTime> setter)
{
Console.WriteLine("DateTime called");
setter(DateTime.Now.AddDays(10));
}
private static void SetValue(Action<double> setter)
{
Console.WriteLine("double called");
setter(13.37);
}
}
Output:
expect long => long called
expect string => string called
expect bool => bool called
expect DateTime => DateTime called
expect double => double called
expect double => double called
Why are these two versions (long, double) ambiguous for the compiler, and why is it still able to call the correct setValue version for the long variable but fails at the double value?