Your Foreach method will be inferred as Foreach(Action<byte> action).
There is no WriteLine overload which takes a single parameter byte and thus it doesn't compile.
What's up with that? Why can't it compile with
Console.WriteLine(int)?
Because Action<int> isn't compatible to Action<byte>
From C# language specification
15.2 Delegate compatibility:
A method or delegate M is compatible with a delegate type D if all of the following 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 with no ref or out modifier), an identity conversion (§6.1.1) or implicit reference conversion (§6.1.6) exists from the parameter type in D to the corresponding parameter type in M.
- For each ref or out parameter, the parameter type in D is the same as the parameter type in M.
- An identity or implicit reference conversion exists from the return type of M to the return type of D.
Overload resolution fails at an identity conversion (§6.1.1) or implicit reference conversion (§6.1.6) exist; None of them exist here. Byte doesn't have identity conversion to int or implicit reference conversion either. So, it can't compile to Console.WriteLine(int).
Why can't it compile with Console.WriteLine(int)?
Because Action<T> is contravariant on type parameter T and contravariance doesn't work for value types. If it were some other reference type, it would have compiled to Console.WriteLine(object) because contravariance do work with 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> does compile even though there is no overload of Console.WriteLine(StringBuilder); It is because reference types supports contravariance.