Почему это строковое свойство показано полностью покрытым, когда оно не должно быть? - PullRequest
2 голосов
/ 31 октября 2011
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 ]

1 голос
/ 31 октября 2011

?? на 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
1 голос
/ 31 октября 2011

Не вдаваясь в IL, сгенерированный этой строкой, я подозреваю, что компилятор выполнил некоторую внутреннюю оптимизацию, которая заставляет вашу "строку B" рассматриваться как один оператор.

Принципиальное различие междуДва утверждения состоят в том, что строка B ссылается на объект, тогда как строка C использует сокращенную ссылку на Num_.Value.


В общем, определенно не стоит беспокоиться о «100% покрытии кода» - как показывает этот пример, иногда, в любом случае, контрольно-измерительные приборы неправильные.Важно то, что большая часть кода покрыта, по крайней мере основные пути выполнения через бизнес-логику.

Охват не заменяет проверки кода другим человеком.

...