Обнуляемый ссылочный тип в C # 8 при использовании классов DTO с ORM

9

Я активировал эту функцию в проекте с классами объекта передачи данных (DTO), как показано ниже:

public class Connection
    {
        public string ServiceUrl { get; set; }
        public string? UserName { get; set; }
        public string? Password { get; set; }
        //... others 
    }

Но я получаю ошибку:

CS8618: Необнуляемое свойство 'ServiceUrl' неинициализировано. Подумайте об объявлении свойства обнуляемым.

Это класс DTO, поэтому я не инициализирую свойства. Это будет обязанностью кода, инициализирующего класс, чтобы гарантировать, что свойства не равны NULL.

Например, звонящий может сделать:

var connection = new Connection
{
  ServiceUrl=some_value,
  //...
}

Мой вопрос: как обрабатывать такие ошибки в классах DTO, когда включен контекст обнуляемости C # 8?

M.Hassan
источник
3
Когда вы выполняете инициализацию конструкции так, как вы показываете, конструктор по умолчанию запускается (инициализируя ServiceUrl своим значением по умолчанию (которое для строк равно null)). Затем выполняется оператор инициализации. Если вы хотите, чтобы он не обнулялся, необходимо
завершить
POCO не означает, что у него нет конструктора или что свойства не инициализированы. Значит Plain Old C# Object. Просто объект, как и любой другой, без наследования от какого-либо специального класса. Я подозреваю, что у вас другой вопрос. Как создать DTO -Data Transfer Objects
Panagiotis Kanavos
This should be the responsibility of the one initializing the class to ensure that the properties are non-nullкласс всегда должен быть в допустимом состоянии. Если nullэто не разрешено, свойство никогда не должно быть нулевым. Возможно, вместо базовой строки вы должны использовать специализированный класс для URL, который может иметь значение Noneили «отсутствует», как класс Option в F #. C # 8 позволяет вам писать такие классы и проверять их с помощью сопоставления с образцом
Panagiotis Kanavos
@Panagiotis Kanavos, класс, в моем случае, имеет ограничение, чтобы быть конструктором без параметров. Так что я должен использовать свойство Initializer: public string ServiceUrl { get; set; } = default! ;. Я надеюсь, что в будущем у Roslyn появится способ справиться с поздней инициализацией за пределами ctor. Я использовал MayBe <T> (как класс Option), но я переключился на обнуляемый ссылочный тип в c # 8 для нового кода.
М.Хасан
НЗТ не являются Maybes, на самом деле, Maybes теперь еще более важно и проще в использовании. Конечно, при условии, что они построены с использованием идиом C #, которые облегчают работу с сопоставлением с образцом
Panagiotis Kanavos

Ответы:

9

Следующее решение рекомендовано EF Core & EF6, см.

1) Путем инициализации null!с прощающим оператором

public string ServiceUrl { get; set; } = null! ;
//or
public string ServiceUrl { get; set; } = default! ;

2) Использование вспомогательного поля:

        private string _ServiceUrl;
        public string ServiceUrl
        {
            set => _ServiceUrl = value;
            get => _ServiceUrl
                   ?? throw new InvalidOperationException("Uninitialized property: " + nameof(ServiceUrl));
        }

M.Hassan
источник
В вопросе упоминается, что он не может использовать !оператора.
Атанасиос Катарас
Я не могу использовать! с типом, но ссылка, которую я упомянул, показывает, как инициализировать с помощью null !. Это обходное решение. Я изменил вопрос.
М.Хасан
8

Если он не обнуляемый, то что может сделать компилятор, когда объект инициализирован?

Значение по умолчанию для строки равно нулю, поэтому вы будете

  1. либо нужно назначить строковое значение по умолчанию в объявлении

    public string ServiceUrl { get; set; } = String.Empty;

  2. Или инициализируйте значение в конструкторе по умолчанию, чтобы избавиться от предупреждения

  3. Используйте !оператор (который вы не можете использовать)

  4. Сделайте это обнуляемым, как упомянуто.

Атанасиос Катарас
источник
4
Или, конечно, добавьте конструктор, принимающий URL-адрес службы в виде строки, которая не может иметь значение NULL.
Джон Скит
ServiceUrl'не может быть = String.Empty. Есть другие свойства сложного типа, которые не могут быть нулевыми, поэтому я использовалdefault : 'public MyClass MyProperty {get; набор; } = по умолчанию! чтобы остановить предупреждение. Этот класс (и другие) является конструктором без параметров и в последнее время инициализируется вне области действия ctor.
М.Хасан
0

Еще одна вещь, которая может пригодиться в некоторых сценариях:

[SuppressMessage("Compiler", "CS8618")]

Может использоваться поверх элемента или целого типа.


Еще одна вещь, которую следует учитывать, - добавление #nullable disableв начало файла, чтобы отключить нулевую ссылку для всего файла.

Шимми Вайцхандлер
источник