为什么编译器会在条件变为三元运算符时发生变化

时间:2014-10-26 20:01:09

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

我有以下示例代码

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行的一部分:

Code coverage

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

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

因此条件运算符中的false从未经过测试(并且无法测试because WaitOne never returns false。一个简单的解决方案就是移出WaitOne的{​​{1}}条件和while内部。所以我的问题是:

  1. 为什么编译器会将条件运算符更改为条件运算符?
  2. 有没有办法阻止编译器这样做,方法是保持条件状态,而不影响其余代码的编译方式?实际上,时间的条件比这更复杂。只要保持这样就会更简单,更易读。

1 个答案:

答案 0 :(得分:2)

C#中的&&运算符是条件运算符,或者通常称为短路运算符。仅当左侧评估为true时才评估右侧操作数。这意味着即使您没有在源代码中看到它,编译代码中也存在一个分支,以便在左侧false的任何时候绕过右侧的评估。

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