Why is overload not working here?
Consider this snippet:
var bytes = new byte[] {0, 0, 0, 0};
bytes.ToList().ForEach(Console.WriteLine);
This will result in a compile-time error:
No overload for 'System.Console.WriteLine(int)' matches delegate 'System.Action<byte>'
You can declare lamdba as a workaround bytes.ToList().ForEach((b => Console.WriteLine(b)))
, but why not overload the permission in the first case?
source to share
Your Foreach method will be output as Foreach(Action<byte> action)
.
There is no overload WriteLine
that takes a single parameter byte
and therefore does not compile.
What's with that? Why can't it compile
Console.WriteLine(int)
?
Because it is Action<int>
not compatible withAction<byte>
From the C # language specification
15.2 Delegate Compatibility:
A method or delegate M is compatible with the type of delegate D if all of them are true:
- D and M have the same number of parameters, and each parameter in D has the same ref or out modifiers as the corresponding parameter in M.
- For each value parameter (a parameter without the ref or out modifier) , an identity conversion (ยง6.1.1) or implicit reference conversion (ยง6.1.6) is performed from the parameter type in D to the corresponding parameter type in M.
- For each ref or out parameter, the type of the parameter in D is the same as the type of the parameter in M.
- There is an identifier or implicit reference conversion from return type M to return type D.
Overload resolution fails on identity conversion (ยง6.1.1) or implicit reference conversion (ยง6.1.6) ; None of them exist here. Byte has no identity conversion for int or implicit reference conversion. Thus, it cannot compile Console.WriteLine(int)
.
Why can't it compile with
Console.WriteLine(int)
?
Because it Action<T>
is contravariant with respect to the type of the parameter T, and contravariance does not work for value types . If it were some other reference type, it would compile with Console.WriteLine(object)
, because contravariance works on a reference type.
For example:
Action<int> action1 = Console.WriteLine;//Compiles to Console.WriteLine(int)
Action<byte> action2 = Console.WriteLine;//Won't compile
Action<StringBuilder> action3 = Console.WriteLine;//Compiles to Console.WriteLine(object)
As you can see, Action<StringBuilder>
compiles even without overloading Console.WriteLine(StringBuilder)
; This is because reference types support contravariance.
source to share