为什么这个字符串属性在不应该被显示时被完全覆盖?

时间:2011-10-31 08:28:30

标签: c# visual-studio-2010 code-coverage

class Program
{
    static void Main(string[] args)
    {
        var x = new Program();
        Console.Write(x.Text);
        Console.Write(x.Num);
        //Console.Write(x.Num);//line A
    }

    private string Text_;
    public string Text
    {
        get
        {
            return Text_ ?? (Text_ = "hello");//line B
        }
    }

    private int? Num_;
    public int Num
    {
        get
        {
            return (int)(Num_ ?? (Num_ = 42));//line C
        }
    }
}

我正在使用Visual Studio 2010获取代码覆盖率结果。它表明线B完全被覆盖,而线C被部分覆盖。我希望B线部分被覆盖,而不是被完全覆盖。 为什么代码覆盖率结果显示B行被完全覆盖?

要证明它对Num属性“正确”工作,请取消注释A行并运行覆盖。它应该显示C行完全被覆盖。

当我将代码重写为更详细的形式(见下文)时,它可以正常工作并报告部分覆盖了Text_。我更喜欢使用前者,为了简洁,我想知道这两种形式是否相同。提前谢谢。

if (Text_ != null)
{
    return Text_;
}
else
{
    return Text_ = "hello";
}

2 个答案:

答案 0 :(得分:1)

如果不进入此行生成的IL,我会怀疑编译器已经进行了一些内部优化,导致您的“B行”被视为单个语句。

两个陈述之间的主要区别在于,B行是指一个对象,而C行是对Num_.Value的简写引用。


一般来说,绝对不值得强调“100%代码覆盖率” - 正如这个例子所示,无论如何,有时仪器是错误的。重要的是覆盖了大多数代码,至少是通过业务逻辑的主要执行路径。

覆盖率不能替代其他人的代码审核。

答案 1 :(得分:1)

?? Nullable<T>扩展到编译器上更复杂的东西,即

a ?? b

真的是

a.HasValue ? a.GetValueOrDefault() : b

现在,由于a在执行的唯一时间内为空/空,因此从未调用a.GetValueOrDefault()。使用字符串(或任何平面引用)时的底层代码更简单。

实际上,只需要两次调用它就可以消除它:

Console.Write(x.Text); // first call; performs init
Console.Write(x.Text); // test once initialized
Console.Write(x.Num); // first call; performs init
Console.Write(x.Num); // test once initialized