【问题标题】:Problems casting objects of type Func<T,T> in C#在 C# 中转换 Func<T,T> 类型的对象时出现问题
【发布时间】: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;
    }

【问题讨论】:

    标签: c# generics lambda


    【解决方案1】:

    在 C# 4 中,变体适用于使用兼容引用类型构造的委托类型。但是它永远不会在类型参数是值类型的委托上工作。

    原因是因为我们不能在不对齐堆栈的情况下做到这一点。考虑你的例子。你有一个Func&lt;int, int&gt;。假设我们允许您将其转换为 Func&lt;int, double&gt;。前者从堆栈中取出 4 个字节并放回 4,导致网络堆栈更改为 0。后者从堆栈中取出 4 并放入 8,导致网络堆栈更改为 4 个字节。函数的调用者将从堆栈中读取 8 个字节,但堆栈上只有 4 个,其余的都是垃圾;结果会是垃圾,堆栈会错位,运行时最终会严重崩溃。

    现在,我们可以通过分配一个修复它的新方法来进行“转换”——它将 4 字节的 int 转换为 8 字节的 double。但这会导致意想不到的坏事。当你说

    Exception x = new Exception();
    object y = x;
    

    你期望会有一个对象——你不期望将 x 转换为对象会导致内存被分配,在事物周围放置一个包装器。您希望“x==y”对于参考比较是正确的。如果我们自动对不兼容的委托类型之间的转换进行修复,那么转换将 (1) 分配内存,并且 (2) 破坏引用相等性。两者都反对参考转换的整个想法。引用转换的全部要点在于它们便宜、快速并且保留引用身份

    如果您想分配一个新的委托来修复现有委托的返回值,您可以随意这样做;我们在代码中明确说明了这一点,以便清楚地表明引用身份正在被破坏,这是一件好事。

    【讨论】:

    • 谢谢 - 我很好奇这个。我曾设想这是一个堆栈管理问题,但不能确定......直到现在。
    【解决方案2】:

    泛型没有这种类型的差异;不是现在,也不是(对于值类型,例如 int/double)在 4.0 中。简单地说,f_int返回double。您能做的最好的事情是:

    Func<int, double> f_double = i => f_int(i);
    

    在返回值中有一个从intdouble 的隐式转换。

    【讨论】:

    • 谢谢! - 让我感到震惊的是,还没有实现像这样直观的东西,因为它使使用 Funct 变得更加困难和费力(我刚刚看到这个:stackoverflow.com/questions/729295/…
    【解决方案3】:

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

    【讨论】:

    • 这很好,但是对于我的项目(在 4.0 中),我需要使用表达式而不仅仅是代表,这也不能编译: Expression > f = x => x * x;
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 2011-10-31
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多