Unexpected results after optimizing switch case in Visual Studio with C#8.0

泄露秘密 提交于 2020-08-22 08:08:12

问题


Today while coding, visual studio notified me that my switch case could be optimized. But the code that I had vs the code that visual studio generated from my switch case does not result in the same outcome.

The Enum I Used:

public enum State
{
    ExampleA,
    ExampleB,
    ExampleC
};

After the following code runs the value is equal to 2147483647.

State stateExample = State.ExampleB;
double value;

switch (stateExample)
{
    case State.ExampleA:
        value = BitConverter.ToSingle(BitConverter.GetBytes((long)2147483646), 0);
        break;
    case State.ExampleB:
        value = BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0);
        break;
    case State.ExampleC:
        value = BitConverter.ToInt16(BitConverter.GetBytes((long)2147483648), 0);
        break;
    default:
        value = 0;
        break;
}

But when visual studio optimized the switch case, the value becomes 2147483648.

State stateExample = State.ExampleB;
double value = stateExample switch
{
    State.ExampleA => BitConverter.ToSingle(BitConverter.GetBytes((long)2147483646), 0), //Commenting this line results in correct value
    State.ExampleB => BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0),
    State.ExampleC => BitConverter.ToInt16(BitConverter.GetBytes((long)2147483648), 0),
    _ => throw new InvalidOperationException()
};

This is just the code with information that reproduced the erroneous output and not actual code that is run in production. What I found weird was that if I comment out the line State.ExampleA in the last code block the correct value is written.

My Question is: Is this a bug? Or am I missing something here?


回答1:


This highlights the difference between a statement and an expression. The switch you had before, was a switch statement and this was the assignment that got run.

value = BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0);

Here you are converting an uint (right hand side) to a double (left hand side). You were actually doing a different conversion in each branch of your switch statement, and this was fine, because well, they are separate assignment statements.

Compare that to what you are doing after the optimisation: the switch statement became a switch expression. And expressions have a single type. What is type of this expression?

stateExample switch
{
    State.ExampleA => BitConverter.ToSingle(BitConverter.GetBytes((long)2147483646), 0), //Commenting this line results in correct value
    State.ExampleB => BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0),
    State.ExampleC => BitConverter.ToInt16(BitConverter.GetBytes((long)2147483648), 0),
    _ => throw new InvalidOperationException()
}

Each branch of the switch returns a different type - float, uint and short respectively. So C# needs to find a type to which all three of these can be implicitly converted. And float is found. C# can't just "figure out" what the switch returns at runtime and work out the conversion to perform "dynamically".

The things returned in each branch has to be first converted to a float. Therefore, the type of the whole expression is float. Finally, you assign the float to value, which is a double.

So the overall conversion is uint -> float -> double, causing a loss of precision.




回答2:


This will work:

double value1 = stateExample switch
    {
        State.ExampleA => (double)BitConverter.ToSingle(BitConverter.GetBytes((long)2147483646), 0), //Commenting this line results in correct value
        State.ExampleB => BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0),
        State.ExampleC => BitConverter.ToInt16(BitConverter.GetBytes((long)2147483648), 0),
        _ => throw new InvalidOperationException()
    };

BitConverter.ToSingle returns float so compiler infers float (between float, uint and short) as output type for the switch expression (and casting uint and short to it) and then casts it's result to double which results in precision loss for ExampleB case.



来源:https://stackoverflow.com/questions/63226902/unexpected-results-after-optimizing-switch-case-in-visual-studio-with-c8-0

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!