Resharper Trap “Convert to 'return' statement”
-
06-07-2019 - |
Question
Given the following routine:
private static object ParseNumber(string token, FieldDefinition def)
{
if (def.Fraction > 0)
return Double.Parse(token);
else
return Int64.Parse(token);
}
Resharper offers me the option to refactor it into a statement with the ternary operator:
private static object ParseNumber(string token, FieldDefinition def)
{
return def.Fraction > 0 ? Double.Parse(token) : Int64.Parse(token);
}
Who can spot the trap?
Solution
Okay, change to previous answer. Because there's an implicit conversion from Int64
to Double
(but not vice versa), that will be the result type of the expression. So when you expect to get a boxed Int64
, you actually get a boxed Double
(but with a value which originally came from Int64.Parse
).
Just in case that's not clear enough, let's change all the return
statements such that they just return a variable. Here's the original code:
private static object ParseNumber(string token, FieldDefinition def)
{
if (def.Fraction > 0)
return Double.Parse(token);
else
return Int64.Parse(token);
}
Convert that appropriately:
private static object ParseNumber(string token, FieldDefinition def)
{
if (def.Fraction > 0)
{
double d = Double.Parse(token);
object boxed = d; // Result is a boxed Double
return boxed;
}
else
{
long l = Int64.Parse(token);
object boxed = l; // Result is a boxed Int64
return boxed;
}
}
And now let's do the same to the version with the conditional operator:
private static object ParseNumber(string token, FieldDefinition def)
{
return def.Fraction > 0 ? Double.Parse(token) : Int64.Parse(token);
}
becomes
private static object ParseNumber(string token, FieldDefinition def)
{
// The Int64.Parse branch will implicitly convert to Double
double d = def.Fraction > 0 ? Double.Parse(token) : Int64.Parse(token);
object boxed = d; // *Always* a Double
return boxed;
}
EDIT: As requested, a bit more information. The type of a conditional expression of the form
X ? Y : Z
depends on the types of Y
and Z
, which I'll call TY
and TZ
. There are a few options:
TY
andTZ
are the same type: result is that type- There's an implicit conversion from
TY
toTZ
but not fromTZ
toTY
: the result is of typeTZ
and the conversion is used if the first branch is used. - There's an implicit conversion from
TZ
toTY
but not fromTY
toTZ
: the result is of typeTY
and the conversion is used if the second branch is used. - There's an implicit conversion in both directions: compile-time error
- There are no conversions either way: compile-time error
Does that help?