Избегайте предупреждения CS8618 при инициализации изменяемого не обнуляемого свойства с проверкой аргумента - PullRequest
2 голосов
/ 16 марта 2020

У меня есть вопрос, касающийся системы ссылочных типов, допускающих обнуляемость , доступной с C# 8.

Предположим, у нас есть C# класс модели домена с изменяемым свойством ссылочного типа, как показано ниже:

public class Person
{

    public string Name { get; set; }

    public Person(string name)
    {         
        Name = name;
    }
}

Пока проблем нет. Но рассмотрим сценарий реального мира, я часто хочу проверять действительность свойства, так как оно является изменяемым c изменяемым свойством, и я должен убедиться, что модель инвариантна при каждом изменении свойства.

public class Person
{
    private string _name;

    public string Name
    {
        get => _name;
        set => _name = value ?? throw new ArgumentNullException("Name is required.");
    }


    public Person(string name)
    {         
        Name = name;
    }
}

Затем компилятор генерирует предупреждение CS8618, в основном говоря:

«Поле, не имеющее значения NULL, не инициализировано. Рассмотрим объявление поля с типом NULL».

Поэтому каждый раз, когда я сталкиваюсь с предупреждением, я Я должен заключить конструктор в следующую директиву прагмы.

#pragma warning disable CS8618
public Person(string name)
{         
    Name = name;
}
#pragma warning restore CS8618

Но я думаю, что делать это всегда излишне и утомительно. Я что-то неправильно использую, или есть лучший способ написать такое свойство без предупреждения?

Конечно, я могу изменить тип свойства на string?, как предполагает компилятор, но условно это не приемлемо в качестве решения, как Person всегда должен иметь ненулевое имя, и мы хотим явно указать о таком инвариантном условии в классе домена.

Другое решение, которое я рассмотрел, состоит в том, чтобы отбросить аргументы logi c и просто полагаться на предупреждение компилятора обнуляемого значения, но это не всегда возможно (Я имею в виду, что часто требуется проверка, отличная от проверки нуля.), В любом случае это просто предупреждение в обычных настройках проекта, поэтому я не думаю, что это хорошее решение.

Ответы [ 2 ]

3 голосов
/ 16 марта 2020

На основе this :

Предупреждения для инициализированных полей Q: Почему предупреждения передаются для полей, которые инициализируются косвенно конструктором или вне конструктора?

A: Компилятор распознает поля, назначенные явно только в текущем конструкторе, и предупреждает о других полях, объявленных как необнуляемые. Это игнорирует другие способы, которыми поля могут быть инициализированы, такие как фабричные методы, вспомогательные методы, установщики свойств и инициализаторы объектов. Мы будем исследовать распознавание общих шаблонов инициализации, чтобы избежать ненужных предупреждений.

Таким образом, с учетом сказанного, пока перемещение назначения непосредственно в конструктор является единственным возможным способом. И, конечно же, использование директивы pragma кажется вполне подходящим для этой ИМО.

2 голосов
/ 16 марта 2020

На данный момент вы можете избежать этого предупреждения, инициализируя поле _name, используя значение по умолчанию с оператором ноль-прощение !, например

private string _name = default!;

или

private string _name = null!;

Для этого существует также открытая проблема GitHub .

Вы также можете объявить _name как string? и указать, что возвращаемое значение свойства Name может null (даже если позволяет тип string?), используя атрибут NotNull

private string? _name;

[NotNull]
public string? Name
{
    get => _name;
    set => _name = value ?? throw new ArgumentNullException("Name is required.");
}

Все должно быть в порядке, иначе компилятор покажет предупреждение перед проверкой logi c будет происходить в сеттере

set => _name = value ?? throw new ArgumentNullException("Name is required.");

Рассмотрим следующий код

var person = new Person(null);

В этом случае вы получите

предупреждение CS8625 : Невозможно преобразовать нулевой литерал в ненулевой ссылочный тип.

до выброса ArgumentNullException.

Если вы установите <TreatWarningsAsErrors>true</TreatWarningsAsErrors> или воспринимаете CS8625 как ошибку, ваше исключение не будет выдано

...