【问题标题】:Is this is an ExpressionTrees bug? #2这是一个 ExpressionTrees 错误吗? #2
【发布时间】:2009-11-09 11:13:01
【问题描述】:

看起来 ExpressionTrees 编译器在许多行为上应该接近 C# 规范,但与 C# 不同的是,它不支持从 decimal 到任何 enum-type 的转换:

using System;
using System.Linq.Expressions;

class Program
{
  static void Main()
  {
    Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor) x;
    ConsoleColor c1 = converter1(7m); // fine

    Expression<Func<decimal, ConsoleColor>> expr = x => (ConsoleColor) x;

    // System.InvalidOperationException was unhandled
    // No coercion operator is defined between types
    // 'System.Decimal' and 'System.ConsoleColor'.

    Func<decimal, ConsoleColor> converter2 = expr.Compile();

    ConsoleColor c2 = converter2(7m);
  }
}

其他很少使用的 C# 显式转换,如 double -&gt; enum-type 存在并按照 C# 规范中的说明工作,但不是 decimal -&gt; enum-type。这是一个错误吗?

【问题讨论】:

    标签: c# .net expression-trees


    【解决方案1】:

    这可能是一个错误,也可能是我的错。对此感到抱歉。

    正确进行十进制转换是在编译器和运行时正确构建表达式树代码最困难的部分之一,因为十进制转换实际上是在运行时作为用户定义的转换实现的,但被视为内置编译器的转换。十进制是唯一具有此属性的类型,因此分析仪中针对这些情况有各种专用齿轮。其实分析器中有一个方法叫IsEnumToDecimalConversion,用来处理可空枚举到可空十进制转换的特殊情况;相当复杂的特例。

    很有可能我没有考虑到某些情况会发生相反的情况,结果生成了错误的代码。感谢您的来信;我会把它发给测试团队,我们会看看我们是否可以进行复制。很有可能,如果这确实是一个真正的错误,这将不会在 C# 4 初始版本中得到修复;在这一点上,我们只处理“编译器触电用户”的错误,以便发布是稳定的。

    【讨论】:

    • 我不知道人类在 C# 语言的制作过程中受到伤害 :)
    • “十进制转换实际上是在运行时实现为用户定义的转换,但被编译器视为内置转换”:这是什么意思,为什么会这样?跨度>
    • @Brian:当您进行表示更改转换时,例如将 int 转换为 double,有一条 IL 指令可以进行该转换。当你做十进制到双精度时,我们实际上会生成代码来调用一个方法来进行转换;小数没有内置到 CLR 的转换指令。但是从 language 的角度来看,我们希望到 appear 的十进制转换是内置到语言的转换;对于内置和用户提供的转换,我们有不同的规则。所以我们必须建立一些特殊的风景来用小数隐藏幕后发生的事情。
    • 好的,这是有道理的。谢谢。
    【解决方案2】:

    还没有真正的答案,我正在调查,但第一行编译为:

    Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor)(int)x;
    

    如果您尝试从之前的 lambda 创建表达式,它将起作用。

    编辑:在 C# 规范 §6.2.2 中,您可以阅读:

    显式枚举转换 两种类型之间的处理由 处理任何参与的枚举类型 作为那个的基础类型 枚举类型,然后执行 隐式或显式数字 结果之间的转换 类型。例如,给定一个枚举类型 E 和基础类型 int, a 处理从 E 到字节的转换 作为显式数字转换 (第 6.2.1 节)从 int 到 byte,以及 处理从字节到 E 的转换 作为隐式数字转换 (§6.1.2)从字节到整数。

    所以从枚举到十进制的显式转换是专门处理的,这就是你得到嵌套转换(int 然后是十进制)的原因。但我不明白为什么编译器在这两种情况下都不以相同的方式解析 lambda 主体。

    【讨论】:

    • 编译器可能会在另一遍中发出嵌套强制转换。在这种情况下,它只会创建一个在运行时失败的转换节点。无论是应该发出嵌套转换的编译器错误还是应该理解十进制到枚举转换的表达式 API 错误都留给读者。我认为发出正确的转换节点是 csc 的责任。
    • 我同意。实际上,您在“expr = lambda”行上得到了编译错误。所以编译器实际上不会尝试发出额外的 Convert 节点或其他任何东西;根据 c# 规范,它认为 lambda 主体是无效的。
    • 对于 double -&gt; enum-type 转换 csc 不会发出 Convert double -&gt; int,只是直接 `double -> enum-type' 并且 ExpressionTrees 编译器可以理解这一点...
    • ControlFlow:那是因为小数不是传统的值类型。它不是通过标准转换而是通过编译器发出的运算符转换为 int。 Romain:实际上我认为编译器发出节点十进制 -> 枚举认为它是有效的。表达式树工厂方法退出了。
    猜你喜欢
    • 2023-03-14
    • 2012-09-18
    • 2012-03-25
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    相关资源
    最近更新 更多