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

d..*_*d.. 2 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;
    }
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 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;
Run Code Online (Sandbox Code Playgroud)

你期望会有一个对象 - 你不希望将x转换为对象会导致内存被分配,并在这个东西周围放置一个包装器.您希望"x == y"对于参考比较是正确的.如果我们自动为不兼容的委托类型之间的转换进行修正,那么转换将(1)分配内存,以及(2)销毁引用相等性.两者都对参考转换的整个想法感到厌恶; 整个参考转换是它们便宜,快速并保持反射性身份.

如果要分配一个新的委托来修复现有委托的返回值,您可以自由地这样做; 我们在代码中明确表示这一点,因此很明显,参照标识正在被销毁,这是一件好事.


Mar*_*ell 6

泛型不具有这种类型的变化; 不是现在,而不是(对于4.0中的值类型,如int/ double).简单地说,f_int 不会返回double.你能做的最好的事情是:

Func<int, double> f_double = i => f_int(i);
Run Code Online (Sandbox Code Playgroud)

它在返回值中具有隐式转换intdouble.