【问题标题】:Why is compiler changing if condition to a ternary operator为什么编译器将条件更改为三元运算符
【发布时间】:2014-10-26 20:01:09
【问题描述】:

我有以下示例代码

public static void Method()
{
    AutoResetEvent autoReset = new AutoResetEvent(false);
    bool canceled = false;

    new Thread(() =>
    {
        Thread.Sleep(1000);
        canceled = true;
        autoReset.Set();
    }).Start();

    do
    {
        Console.WriteLine("Doing something");
    } while (autoReset.WaitOne() && !canceled);

    Console.WriteLine("Completed");
}

我正在努力实现 100% 的代码覆盖率。所以我只是做了一个简单的测试(什么都不测试,但这不是重点),运行它并分析代码覆盖率:

[TestMethod]
public void TestMethod1()
{
    Program.Method();
}

代码覆盖率告诉我只执行了while 行的一部分:

经过一番研究,我尝试反编译代码,发现编译器正在将我的do while更改为:

do
{
    Console.WriteLine("Doing something");
    flag = (!autoResetEvent.WaitOne() ? false : !flag1);
}
while (flag);

因此,条件运算符中的false 永远不会被测试(并且不可能测试because WaitOne never returns false。一个简单的解决方案就是将while 条件的WaitOne 移出并放在do 内。所以我的问题是:

  1. 为什么编译器将 and 条件更改为条件运算符?
  2. 有没有一种方法可以防止编译器执行此操作,方法是保持当前条件不变且不影响其余代码的编译方式?实际上,while 中的条件比这更复杂。像这样保持它会更简单,更易读。

【问题讨论】:

  • 为什么你认为这是编译器而不是反编译器的结果?
  • 好问题。我认为这是编译器的结果,因为它与我没有被覆盖到 100% 的原因是一致的。贴IL证明是编译器的结果吗?
  • 代码覆盖率是一个非常危险的指标。 100% 的覆盖率不会告诉你代码或测试用例的质量——即使是 100% 的代码覆盖率,你仍然可能会错过关键的测试用例和错误。不要为了获得 100% 的覆盖率而拍摄。

标签: c# .net visual-studio unit-testing code-coverage


【解决方案1】:

C# 中的&& 运算符条件运算符,或更常见的称为短路运算符。仅当左侧计算结果为 true 时,才计算右侧操作数。这意味着即使您在源代码中看不到它,编译后的代码中也存在一个分支,以在左侧为 false 时绕过右侧的评估。

这会以多种方式影响代码覆盖率。如果您通过branch coverage 进行测量,那么实现100% 覆盖率的唯一方法是创建一个测试,其中autoResetEvent.WaitOne() 返回false(例如,通过mocking)。但是,如果您通过其他指标(例如语句覆盖率)来衡量覆盖率,您可能根本不需要做任何事情来实现 100% 的覆盖率。

【讨论】:

  • 所以如果我理解正确的话,shot-circuiting 只存在于 C# 中而不存在于 IL 中?
  • CIL 中没有&& 操作码,因此编译器使用分支指令将其转换为等效行为。
  • 太棒了!这就说得通了。感谢您的回答
猜你喜欢
  • 2015-12-23
  • 1970-01-01
  • 2022-11-08
  • 2020-06-19
  • 1970-01-01
  • 2017-08-26
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多