在C#</t,t>中转换类型为Func <t,t>的对象时出现问题

时间:2010-01-09 20:40:28

标签: c# generics lambda

为什么不编译?我想有办法解决这个问题;只是好奇。

谢谢!

    static void Main(string[] args)
    {
        Func<int, int> f_int = n => n * n;
        Func<int, double> f_double = (Func<int, double>)f_int;
    }

3 个答案:

答案 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);

在返回值中隐式转换为intdouble

答案 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);