using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
Expression<Func<float, uint>> expr = x => (uint) x;
Func<float,uint> converter1 = expr.Compile();
Func<float,uint> converter2 = x => (uint) x;
var aa = converter1(float.MaxValue); // == 2147483648
var bb = converter2(float.MaxValue); // == 0
}
}
在为此次转化编译Expression.Convert
时,可以建立相同的不同行为:
Single -> UInt32
Single -> UInt64
Double -> UInt32
Double -> UInt64
看起来很奇怪,不是吗?
&lt; ===添加了一些我的研究===&gt;
我使用 DynamicMethod Visualizer 查看了已编译的DynamicMethod
MSIL代码,并从编译的DynamicMethod
获取了Expression<TDelegate>
的一些反射黑客:
Expression<Func<float, uint>> expr = x => (uint) x;
Func<float,uint> converter1 = expr.Compile();
Func<float,uint> converter2 = x => (uint) x;
// get RTDynamicMethod - compiled MethodInfo
var rtMethodInfo = converter1.Method.GetType();
// get the field with the reference
var ownerField = rtMethodInfo.GetField(
"m_owner", BindingFlags.NonPublic | BindingFlags.Instance);
// get the reference to the original DynamicMethod
var dynMethod = (DynamicMethod) ownerField.GetValue(converter1.Method);
// show me the MSIL
DynamicMethodVisualizer.Visualizer.Show(dynMethod);
我得到的是这个MSIL代码:
IL_0000: ldarg.1
IL_0001: conv.i4
IL_0002: ret
同等的C#编译方法有这个主体:
IL_0000: ldarg.0
IL_0001: conv.u4
IL_0002: ret
现在有人看到ExpressionTrees编译的转换代码不是有效的吗?
答案 0 :(得分:11)
这是明显一个错误,它在今天的C#4.0版本中重现。感谢您提请我们注意。很有可能这个问题不在最终版本发布之前做出修复的障碍;在这个最后阶段,我们只采取了非常高优先级的解决方案,我们有信心不会破坏发布的稳定性。更有可能的是,修复将使其成为未来的服务版本;但当然没有承诺。
答案 1 :(得分:2)
我在这里看不到问题。在理想情况下,您应该在两种情况下都出现编译错误。因为结果实际上是一个无声的溢出。 例如,以下简单地不会编译:
var test = (uint)(float.MaxValue);
首先做错事时,你获得不同的价值观真的很重要吗?如果您修改代码以使用检查转换(x =&gt; checked((uint)x)),您将在两种情况下获得相同的结果 - 运行时异常。
答案 2 :(得分:0)
我不确定这是不是一个错误,但我可以指出差异的方向:
这两种方法的构建方式不同。编译为converter1的表达式具有类型DynamicMethod的目标方法。分配给converter2的lambda方法的目标方法是 RuntimeMethodInfo 。
两者都是通过不同的机制编译JIT。正如我所说,不能说出为什么他们有不同的行为,但这可能是造成差异的原因。
编辑这是它编译的内容(使用Reflector的代码)。
ParameterExpression CS$0$0000;
Func<float, uint> converter1 = Expression.Lambda<Func<float, uint>>(Expression.Convert(CS$0$0000 = Expression.Parameter(typeof(float), "x"), typeof(uint)), new ParameterExpression[] { CS$0$0000 }).Compile();
Func<float, uint> converter2 = delegate (float x) { return (uint) x; };
uint aa = converter1(float.MaxValue);
uint bb = converter2(float.MaxValue);
为什么结果不同会有所帮助。