看起来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 -> enum-type
)存在并且按照C#规范中的说明工作,但不是decimal -> enum-type
。这是一个错误吗?
答案 0 :(得分:16)
这可能是一个错误,这可能是我的错。对不起。
正确获取十进制转换是在编译器和运行时中构建表达式树代码最难的部分之一,因为十进制转换实际上是在运行时实现为用户定义的转换,但被视为内置编译器的转换。十进制是唯一具有此属性的类型,因此在这些情况下,分析仪中有各种专用齿轮。事实上,在分析器中有一个名为IsEnumToDecimalConversion的方法来处理可空的枚举到可以为空的十进制转换的特殊情况;非常复杂的特殊情况。
很有可能我没有考虑到其他方面的情况,并因此产生了错误的代码。谢谢你的说明;我会把这个发送给测试团队,我们会看看我们是否能得到一个重新开始。可能性很好,如果这确实是一个真正的错误,这将不适用于C#4初始版本;在这一点上,我们只采取“用户被编译器触电”的错误,以便释放稳定。
答案 1 :(得分:3)
还没有真正的答案,我正在调查,但第一行编译为:
Func<decimal, ConsoleColor> converter1 = x => (ConsoleColor)(int)x;
如果您尝试从上一个lambda创建表达式,它将起作用。
编辑:在C#规范,§6.2.2中,您可以阅读:
显式枚举转换 两种类型之间的处理方式 治疗任何参与的枚举类型 作为其基本类型 枚举类型,然后执行 隐式或显式数字 结果之间的转换 类型。例如,给定枚举类型 E with和底层类型的int,a 处理从E到字节的转换 作为显式数字转换 (§6.2.1)从int到byte,和a 处理从字节到E的转换 作为隐式数字转换 (§6.1.2)从byte到int。
因此,具体处理从枚举到十进制的显式转换,这就是为什么你得到嵌套转换(int然后十进制)。但我无法理解为什么编译器在两种情况下都不会以相同的方式解析lambda体。