【发布时间】:2010-01-09 20:40:28
【问题描述】:
为什么不编译?我想有办法解决这个问题;只是好奇。
谢谢!
static void Main(string[] args)
{
Func<int, int> f_int = n => n * n;
Func<int, double> f_double = (Func<int, double>)f_int;
}
【问题讨论】:
为什么不编译?我想有办法解决这个问题;只是好奇。
谢谢!
static void Main(string[] args)
{
Func<int, int> f_int = n => n * n;
Func<int, double> f_double = (Func<int, double>)f_int;
}
【问题讨论】:
在 C# 4 中,变体适用于使用兼容引用类型构造的委托类型。但是它永远不会在类型参数是值类型的委托上工作。
原因是因为我们不能在不对齐堆栈的情况下做到这一点。考虑你的例子。你有一个Func<int, int>。假设我们允许您将其转换为 Func<int, double>。前者从堆栈中取出 4 个字节并放回 4,导致网络堆栈更改为 0。后者从堆栈中取出 4 并放入 8,导致网络堆栈更改为 4 个字节。函数的调用者将从堆栈中读取 8 个字节,但堆栈上只有 4 个,其余的都是垃圾;结果会是垃圾,堆栈会错位,运行时最终会严重崩溃。
现在,我们可以通过分配一个修复它的新方法来进行“转换”——它将 4 字节的 int 转换为 8 字节的 double。但这会导致意想不到的坏事。当你说
Exception x = new Exception();
object y = x;
你期望会有一个对象——你不期望将 x 转换为对象会导致内存被分配,在事物周围放置一个包装器。您希望“x==y”对于参考比较是正确的。如果我们自动对不兼容的委托类型之间的转换进行修复,那么转换将 (1) 分配内存,并且 (2) 破坏引用相等性。两者都反对参考转换的整个想法。引用转换的全部要点在于它们便宜、快速并且保留引用身份。
如果您想分配一个新的委托来修复现有委托的返回值,您可以随意这样做;我们在代码中明确说明了这一点,以便清楚地表明引用身份正在被破坏,这是一件好事。
【讨论】:
泛型没有这种类型的差异;不是现在,也不是(对于值类型,例如 int/double)在 4.0 中。简单地说,f_int不返回double。您能做的最好的事情是:
Func<int, double> f_double = i => f_int(i);
在返回值中有一个从int 到double 的隐式转换。
【讨论】:
Delgates 不能像这样转换,因为 double 不继承自 int 或反之亦然。
解决方法只是使用双精度将结果存储在:
double r = f_int(a);
或在 C# 4.0 中使用 dynamic:
Func<dynamic, dynamic> f = n => n*n;
double d = f(2.0);
int i = f(2);
【讨论】: