jdp*_*nix 3 c# generics overloading type-inference covariance
请考虑以下代码段:
var bytes = new byte[] {0, 0, 0, 0};
bytes.ToList().ForEach(Console.WriteLine);
Run Code Online (Sandbox Code Playgroud)
这将导致编译时错误:
No overload for 'System.Console.WriteLine(int)' matches delegate 'System.Action<byte>'
Run Code Online (Sandbox Code Playgroud)
您可以将lamdba声明为变通方法,bytes.ToList().ForEach((b => Console.WriteLine(b)))但为什么在第一种情况下不会使重载解析工作?
您的Foreach方法将被推断为Foreach(Action<byte> action).
没有WriteLine重载需要一个参数byte,因此它不能编译.
那是怎么回事?为什么不能编译
Console.WriteLine(int)?
因为Action<int>不兼容Action<byte>
来自C#语言规范
15.2代表兼容性:
如果满足以下所有条件,则方法或委托M与委托类型D兼容:
在身份转换(第6.1.1节)或隐式引用转换(第6.1.6 节)存在时,重载解析失败; 这里没有一个存在.字节也没有到int或隐式引用转换的标识转换.所以,它无法编译到Console.WriteLine(int).
为什么不能编译
Console.WriteLine(int)?
因为Action<T>类型参数T是逆变的,并且逆变量对值类型不起作用.如果它是一些其他引用类型,它将编译为,Console.WriteLine(object)因为逆变确实与引用类型一起工作.
例如:
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)
Run Code Online (Sandbox Code Playgroud)
正如你所看到的Action<StringBuilder>那样,即使没有重载也会编译Console.WriteLine(StringBuilder); 这是因为参考类型支持逆变.
| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |