Что значит ноль!заявление значит? - PullRequest
0 голосов
/ 16 февраля 2019

Я недавно видел следующий код:

public class Person
{
    //line 1
    public string FirstName { get; }
    //line 2
    public string LastName { get; } = null!;
    //assign null is possible
    public string? MiddleName {get; } = null;

    public Person(string firstName, string lastName, string middleName)
    {
        FirstName = firstName;
        LastName = lastName;
        MiddleName = middleName;
    }

    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
        MiddleName = null;
    }
}

По сути, я пытаюсь покопаться в новых возможностях c # 8.Одним из них является NullableReferenceTypes.На самом деле уже много статей и информации об этом.Например, эта статья довольно хороша.Но я не нахожу никакой информации об этом новом утверждении null! Может ли кто-нибудь дать мне объяснение этому?Почему я должен использовать это?И в чем разница между line1 и line2?

Ответы [ 2 ]

0 голосов
/ 16 февраля 2019

Когда включена функция «Обнуляемые ссылочные типы», компилятор отслеживает, какие значения в вашем коде могут быть нулевыми или нет.Бывают случаи, когда у компилятора может быть недостаточно знаний.

Например, вы можете использовать шаблон отложенной инициализации, где конструктор не инициализирует все поля с фактическими (не нулевыми) значениями, но вывсегда вызывайте метод инициализации, который гарантирует, что поля не равны NULL.В этом случае вы сталкиваетесь с компромиссом:

  • , если вы пометите поле как обнуляемое, компилятор будет доволен, но вам не обязательно проверять наличие нуля при использовании поля,
  • если вы оставите поле как необнуляемое, компилятор будет жаловаться, что оно не инициализируется конструкторами (вы можете подавить это с помощью null!), тогда поле можно использовать без проверки нуля.

Обратите внимание, что с помощью оператора подавления ! вы рискуете.Представьте, что вы на самом деле инициализируете не все поля так, как вы думали.Тогда использование null! для инициализации поля скрывает тот факт, что null проскальзывает. Некоторый ничего не подозревающий код может получить null и, следовательно, потерпеть неудачу.

В целом, у вас могут быть некоторыезнание предмета: «если я проверил определенный метод, то я знаю, что какое-то значение не равно нулю»:

if (CheckEverythingIsReady())
{
   // you know that `field` is non-null, but the compiler doesn't. The suppression can help
   UseNonNullValueFromField(this.field!);
}

Опять же, вы должны быть уверены в инварианте вашего кода, чтобы сделать это («Я знаю лучше«).

0 голосов
/ 16 февраля 2019

Ключом к пониманию того, что означает null!, является понимание оператора !.Возможно, вы использовали его раньше как оператор «не».Но начиная с C # 8.0 оператор также может использоваться в типе для управления Nullabilty

Что такое оператор ! при использовании в типе?

Оператор !, когда используетсядля типа, называется оператором Null Forgiving [ docs ].Он был введен в C # 8.0


Техническое объяснение

Типичное использование

Принимая это определение:

class Person
{
  public string? MiddleName;
}

Использование будет:

void LogPerson(Person person)
{
    Console.WriteLine(person.MiddleName.Length);  // WARNING: may be null
    Console.WriteLine(person.MiddleName!.Length); // No warning
}

Этот оператор в основном отключает нулевые проверки компилятора.

Внутренняя работа

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

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

  • Nullable - Может быть нулевым.
  • Не обнуляется - Не может быть нулевым.

Начиная с C # 8.0 все ссылочные типы не обнуляются.по умолчанию.

«Обнуляемость» может быть изменена этими двумя новыми операторами типов:

  • ! = От Nullable до Non-Nullable
  • ? = От Non-Nullable до Nullable

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

? Использование оператора.

  1. Nullable string? x;

    • x является ссылочным типом - поэтому по умолчанию не обнуляется.
    • Мы применяем оператор ? - что делает его обнуляемым.
    • x = null Работает нормально.
  2. Не обнуляемый string y;

    • y является ссылочным типом - поэтому по умолчанию не обнуляется.
    • y = null Создает предупреждение, поскольку вы назначаете нулевое значение чему-то, что не должно быть нулевым.

! Использование оператора.

string x;
string? y = null;
  1. x = y

    • Незаконно!- Warning: "y" may be null
    • Левая сторона задания не допускает обнуления, но правая сторона обнуляется.
  2. x = y!

    • Legal!
    • Правая и левая части присвоения не могут быть обнулены.
    • Работает с y! Применяет оператор ! к y, что делает его не-nullable.

ПРЕДУПРЕЖДЕНИЕ Оператор ! отключает проверки компилятора только на уровне системы типов - во время выполнения,значение все еще может быть нулевым.

Это анти-шаблон.

Вы должны попробовать до избегать , используя ! Null-Forgiving-Operator.

Существуют допустимые варианты использования (подробно описанные ниже), такие как модульные тесты, в которых этот оператор подходит для использования.Тем не менее, в 99% случаев вам лучше найти альтернативное решение.Пожалуйста, не добавляйте десятки ! в ваш код, просто чтобы замолчать предупреждения.Подумайте, действительно ли ваше дело оправдывает использование.

Используйте - но с осторожностью.Если нет конкретной цели / варианта использования, предпочитайте не использовать его.

Это сводит на нет эффекты нулевой безопасности, которые вы гарантируете компилятором.

Использованиеоператор ! будет очень трудно находить ошибки. Если у вас есть свойство, помеченное как необнуляемое, вы можете использовать его безопасно.Но во время выполнения вы неожиданно сталкиваетесь с NullReferenceException и чесаете голову.Поскольку значение фактически становится нулевым после обхода проверок компилятором с помощью !.

Почему тогда существует этот оператор?

  • В некоторых крайних случаях компилятор не можетобнаружить, что значение NULL может быть ненулевым.
  • Упрощенная миграция унаследованного кода.
  • В некоторых случаях вам просто все равно, станет ли что-либо пустым.
  • При работе с юнит-тестами вы можете проверить поведение кода, когда null проходит.

Отвечая конкретно на ваш вопрос.

Итакчто означает null!

Он сообщает компилятору, что null не является значением null.Звучит странно, не правда ли?

Это то же самое, что и y! из приведенного выше примера. Это выглядит странно, так как вы применяете оператор к null литерал .Но концепция та же.

Разбирая происходящее.

public string LastName { get; } = null!;

Эта строка определяет свойство класса, не допускающее обнуления, с именем LastName типа string.Поскольку он не обнуляем, вы технически не можете присвоить ему значение null - очевидно.

Но вы просто делаете это - назначаете null на LastName - используя оператор !.Потому что null! не равен нулю - поскольку компилятор обеспокоен нулевой безопасностью.

...