c# - 使用 C#8.0 在 Visual Studio 中优化 switch case 后出现意外结果

标签 c# c#-8.0

今天在编码时,Visual Studio 通知我我的 switch case 可以优化。但是我拥有的代码与 Visual Studio 从我的 switch case 生成的代码并不会产生相同的结果。
我使用的枚举:

public enum State
{
    ExampleA,
    ExampleB,
    ExampleC
};
以下代码运行后,该值等于 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;
}
但是当visual studio优化switch case时,值变成了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()
};
这只是带有重现错误输出信息的代码,而不是在生产中运行的实际代码。我发现奇怪的是,如果我注释掉 State.ExampleA 行在最后一个代码块中写入了正确的值。
我的问题是:这是一个错误吗?或者我在这里错过了什么?

最佳答案

这突出了语句和表达式之间的区别。你之前的 switch 是一个 switch 语句,这是运行的赋值。

value = BitConverter.ToUInt32(BitConverter.GetBytes((long)2147483647), 0);
在这里,您正在转换 uint (右侧)到 double (左手边)。实际上,您在 switch 语句的每个分支中都进行了不同的转换,这很好,因为它们是单独的赋值语句。
将其与优化后的操作进行比较:switch 语句变成了 switch 表达式。表达式只有一种类型。这个表达式的类型是什么?
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()
}
开关的每个分支返回不同的类型 - float , uintshort分别。 所以 C# 需要找到一个类型,这三个都可以隐式转换为 .和float被发现。 C# 不能仅仅“弄清楚”开关在运行时返回的内容,并计算出“动态”执行的转换。
每个分支中返回的东西必须首先转换为 float .因此,整个表达式的类型为float .最后,分配 floatvalue ,这是一个 double .
所以整体转换为uint -> float -> double ,导致精度损失。

关于c# - 使用 C#8.0 在 Visual Studio 中优化 switch case 后出现意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63226902/

相关文章:

c# - 流畅的 API = 数据注释?

c# - netcoreapp3.1 似乎引用了 C# 7.3 而不是 8,如记录的那样

c# - 可空引用类型和 ToString() 重载

c# - 用于检测 C# 8/可为空引用类型的编译器指令

c# - 为什么 IAsyncEnumerator 在 C#8 中没有 Reset 方法?

c# - SharpSVN 使用 'SvnLookClient' 获取提交后 Hook

c# - 数据绑定(bind)依赖属性到数据对象

c# - 是否可以使用 C#7 绑定(bind)到 WPF 中的 ValueTuple 字段

C#8 : Switch ref expressions

c# - 使用 EnumeratorCancellation 返回 AsyncEnumerable 或循环 WithCancellation 有什么区别