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
}
}
Same different behavior can be founded when compiling Expression.Convert
for this conversions:
Single -> UInt32
Single -> UInt64
Double -> UInt32
Double -> UInt64
Looks strange, isn't it?
<=== Added some my research ===>
I'm looked at the compiled DynamicMethod
MSIL code using DynamicMethod Visualizer and some reflection hack to get DynamicMethod
from the compiled 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);
And what I get is this MSIL code:
IL_0000: ldarg.1
IL_0001: conv.i4
IL_0002: ret
And the equal C#-compiled method has this body:
IL_0000: ldarg.0
IL_0001: conv.u4
IL_0002: ret
Do anybody see now that ExpressionTrees compiles not valid code for this conversion?
This is clearly a bug, and it reproduces in today's build of C# 4.0. Thank you for bringing it to our attention. Odds are good that this issue will not make the bar for fixing before the final release; at this late stage we are taking only very high-priority fixes that we have confidence will not destabilize the release. What's more likely is that a fix will make it into a future service release; but of course, no promises.
I don't see a problem here. In the ideal case, you should get a compilation error in both situations. Becuase the result is actually a silent overflow. For example, the following simply would not compile:
var test = (uint)(float.MaxValue);
Does it really matter that you get different values when doing a wrong thing in the first place? If you modify your code to use checked conversion ( x => checked((uint)x) ), you'll get the same result in both scenarios - a run time exception.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With