为什么不编译?我想有办法解决这个问题;只是好奇。
谢谢!
static void Main(string[] args)
{
Func<int, int> f_int = n => n * n;
Func<int, double> f_double = (Func<int, double>)f_int;
}
答案 0 :(得分:7)
在C#4中,variance将适用于使用兼容引用类型构造的委托类型。但是它永远不会在类型参数是值类型的委托上工作。
原因是因为我们不能在没有错位堆栈的情况下做到这一点。考虑你的例子。你有一个Func<int, int>
。假设我们允许您将其转换为Func<int, double>
。前者从堆栈中取出4个字节并重新打开4个,导致净堆栈更改为0.后者需要4个关闭并打开8个,导致净堆栈更改为4个字节。该函数的调用者将从堆栈中读取8个字节,但堆栈中只有4个字节,其余的是垃圾;结果将是垃圾,堆栈将不对齐,运行时最终会崩溃。
现在,我们可以通过分配一个修复它的新方法来进行“转换” - 这需要4字节的int并将其转换为8字节的双精度。但这会导致出乎意料的不良情况。当你说
Exception x = new Exception();
object y = x;
你希望有一个对象 - 你不希望将x转换为对象会导致内存被分配,并在这个东西周围放置一个包装器。您希望“x == y”对于参考比较是正确的。如果我们自动为不兼容的委托类型之间的转换进行修正,那么转换将(1)分配内存,以及(2)销毁引用相等性。两者都对参考转换的整个想法感到厌恶;引用转换的整个点是它们便宜,快速并且保留了反复身份。
如果要分配一个新的委托来修复现有委托的返回值,您可以自由地这样做;我们在代码中明确表示这一点,因此很明显,参照标识正在被销毁,这是一件好事。
答案 1 :(得分:6)
泛型没有这种差异;不是现在,而不是(对于4.0中的int
/ double
等值类型)。简单地说,f_int
不会返回double
。你能做的最好的是:
Func<int, double> f_double = i => f_int(i);
在返回值中隐式转换为int
到double
。
答案 2 :(得分:1)
Delgates不能像这样转换,因为double不会从int继承,反之亦然。
变通方法只是使用double来存储结果:
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);