Поделиться через


Разрешение предупреждений с нулевыми значениями

Цель предупреждений, допускающих значение NULL, заключается в том, чтобы свести к минимуму вероятность того, что приложение создает System.NullReferenceException исключение при запуске. Для достижения этой цели компилятор использует статический анализ и выдает предупреждения при наличии конструкций кода, которые могут привести к исключениям ссылок null. Вы предоставляете компилятору информацию для его статического анализа путем применения заметок типа и атрибутов. Эти аннотации и атрибуты описывают наличие значения null у аргументов, параметров и членов ваших типов. В этой статье описаны различные методы устранения предупреждений, допускающих значение NULL, которые компилятор создает из статического анализа. Описанные здесь методы предназначены для общего кода C#. Узнайте, как работать с допускаемыми значением NULL ссылочными типами и Entity Framework Core в работе с допускаемыми значением NULL ссылочными типами.

Ссылочные типы, допускающие значение NULL, включая операторы ? и !, разрешены только в том случае, если для контекста, допускаемого значение NULL, задано значение enable или annotations. Контекст, допускающий значение NULL, можно задать с помощью параметра компилятора Nullable в файле проекта или с помощью #nullable pragma в исходном коде.

В этой статье рассматриваются следующие предупреждения компилятора:

  • Вызываемое значение CS8597 - может иметь значение NULL.
  • CS8598 - Оператор подавления не допускается в этом контексте
  • CS8600 - Преобразование null-литерала или возможного значения NULL в тип, не допускающий NULL.
  • CS8601 - Возможное присвоение нулевой ссылки.
  • CS8602 - Разыменование возможно нулевой ссылки.
  • CS8603 - Возможное возвращение пустой ссылки.
  • Возможный аргумент null ссылки для параметра CS8604 - .
  • CS8605 - Распаковка возможно нулевого значения.
  • CS8607 - Возможное значение NULL не может использоваться для типа, помеченного с помощью [NotNull] или [DisallowNull]
  • Значение NULL типов ссылок в типе CS8608 - не соответствует переопределенным элементу.
  • Ошибка CS8609 - Нулевизна ссылочного типа в возвращаемом типе не соответствует переопределенному элементу.
  • CS8610 - Нулевое значение ссылочных типов в параметре типа не соответствует члену с переопределением.
  • CS8611 - "Nullability" ссылочных типов в параметре типа не соответствует объявлению частичного метода.
  • NULL-способность ссылочных типов в типе не соответствует неявно реализованным членам CS8612
  • CS8613 - Аннотация null значения ссылочных типов в возвращаемом типе не соответствует неявно реализованному члену.
  • CS8614 - Способность ссылочных типов в параметре не совпадает с неявно реализованным членом.
  • Значение NULL типов ссылок в типе CS8615 - не совпадает с реализованным элементом.
  • CS8616 - Обнуляемость ссылочных типов в возвращаемом типе не соответствует реализованному члену.
  • CS8617 - Nullability ссылочных типов в типе параметра не соответствует реализованному члену.
  • Переменная CS8618 - , не допускающая значение NULL, должна содержать ненулевое значение при выходе из конструктора. Рассмотрите возможность объявления его как допускающего значение NULL.
  • CS8619 - Указание нулевой допустимости ссылочных типов не соответствует целевому типу.
  • CS8620 - Аргумент нельзя использовать для параметра из-за различий в обнулению ссылочных типов.
  • CS8621 - Допустимость значений null для ссылочных типов в возвращаемом типе не соответствует целевому делегату (возможно, из-за атрибутов допустимости null).
  • Предупреждение CS8622 - null-способность ссылочных типов параметра не соответствует целевому делегату (возможно, из-за атрибутов null-способности).
  • CS8623 - явное применение System.Runtime.CompilerServices.NullableAttribute запрещено.
  • CS8624 - Аргумент не может быть использован в качестве выходного из-за различий в допустимости значений NULL ссылочных типов.
  • CS8625 - Не удается преобразовать литерал NULL в ненулевой ссылочный тип.
  • CS8628 - Невозможно использовать тип ссылки, допускающий значение NULL, при создании объекта.
  • CS8629 - Тип значения, допускающий NULL, может иметь значение NULL.
  • CS8631 - Тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Значение NULL аргумента типа не соответствует типу ограничения.
  • CS8632 - Аннотация для ссылочных типов, допускающих значение NULL, должна использоваться только в коде в контексте аннотаций #nullable.
  • CS8633 - Неопределенность в ограничениях для типового параметра метода не соответствует ограничениям для типового параметра метода интерфейса. Рассмотрите использование явной реализации интерфейса вместо этого.
  • CS8634 - Тип нельзя использовать в качестве параметра типа в обобщённом типе или методе. Показатель допустимости значения NULL аргумента типа не соответствует ограничению 'class'.
  • CS8636 - Недопустимый параметр для /nullable; должно быть disable, enable, warnings или annotations
  • CS8637 - Ожидаемые enable, disableили restore
  • CS8639 - Оператор typeof не может использоваться для ссылочного типа, допускающего значение null
  • CS8643 - Нулевое значение ссылочных типов в явном спецификаторе интерфейса не соответствует интерфейсу, реализуемому типом.
  • CS8644Тип не реализует член интерфейса. Возможность ссылочных типов принимать значение NULL в интерфейсе, реализованном базовым типом, не соответствует.
  • CS8645 - Член уже указан в списке интерфейсов в типе с разной нулевой доступностью ссылочных типов.
  • CS8655 - Выражение коммутатора не обрабатывает некоторые входные данные NULL (это не является исчерпывающим).
  • Объявления частичного метода CS8667 - имеют несогласованность аннулируемости в ограничениях для параметра типа.
  • CS8670 - Инициализатор объекта или коллекции неявно разыменовывает потенциально нулевой элемент.
  • CS8714 - Этот тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Нулевое значение аргумента типа не соответствует ограничению 'notnull'.
  • Параметр CS8762 - должен иметь ненулевое значение при выходе.
  • CS8763 - Метод, помеченный как [DoesNotReturn], не должен возвращать.
  • Ошибка CS8764: Нулевость типа возвращаемого значения не совпадает с типом переопределенного члена (возможно, из-за атрибутов нулевости).
  • CS8765 - Нулевость типа параметра не совпадает с переопределенным элементом (возможно, из-за атрибутов нулевости).
  • CS8766 - Нулевая допустимость ссылочных типов в возвращаемом типе не совпадает с неявно реализованным членом (возможно, из-за атрибутов допустимости null).
  • Значение NULL типов ссылок в типе параметра CS8767 - не совпадает с неявно реализованным элементом (возможно, из-за атрибутов nullability).
  • CS8768 - Свойство nullability ссылочного типа в возвращаемом значении не соответствует реализованному члену (возможно, из-за атрибутов nullability).
  • CS8769 - Нулевость ссылочных типов в типе параметра не соответствует реализованному члену (возможно, из-за атрибутов нулевости).
  • Метод CS8770 - не имеет примечаний [DoesNotReturn] для сопоставления реализованного или переопределенного элемента.
  • Элемент CS8774 - должен иметь ненулевое значение при выходе.
  • CS8776 - Элемент нельзя использовать в этом атрибуте.
  • Элемент CS8775 - должен иметь ненулевое значение при выходе.
  • Параметр CS8777 - должен иметь ненулевое значение при выходе.
  • CS8819 - Аннотации допускающих значение null ссылочных типов в возвращаемом типе не соответствуют объявлению частичного метода.
  • Параметр CS8824 - должен иметь ненулевое значение при выходе, так как параметр не имеет значения NULL.
  • CS8825Возвращаемое значение должно быть не NULL, так как параметр не является null.
  • CS8847 - Выражение коммутатора не обрабатывает некоторые входные данные NULL (это не является исчерпывающим). Однако шаблон с предложением "when" может успешно соответствовать этому значению.

Заметка

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

Вы устраняете почти все предупреждения, используя один из пяти методов.

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

Если вы не знакомы с использованием ссылочных типов, допускающих значение NULL, общие сведения об этих типах предоставляют обзорную информацию о том, какие задачи решают ссылочные типы, допускающие значение NULL, и как они помогают предупреждать о возможных ошибках в вашем коде. Вы также можете проверить руководство по миграции на типы ссылок, допускающие значение NULL,, чтобы узнать больше о включении ссылочных типов, допускающих значение NULL, в существующем проекте.

Настройка контекста допустимости значений NULL

Следующие предупреждения указывают на то, что контекст, допускающий значение NULL, неправильно задан:

  • CS8632 - Аннотация для ссылочных типов, допускающих значение NULL, должна использоваться только в коде в контексте аннотаций #nullable.
  • CS8636 - Недопустимый параметр для /nullable; должно быть disable, enable, warnings или annotations
  • CS8637 - Ожидаемые enable, disableили restore

Неправильный синтаксис заметки

Эти ошибки и предупреждения указывают на неправильное использование ! или ? заметки.

  • CS8598 - Оператор подавления не допускается в этом контексте
  • CS8623 - Явное применение System.Runtime.CompilerServices.NullableAttribute запрещено.
  • CS8628 - Не удается использовать ссылочный тип, допускающий значение NULL, в создании объекта.
  • CS8639 - Оператор typeof нельзя использовать для ссылочного типа, допускающего значение null,

Заметка ? в объявлении указывает, что переменная может иметь значение NULL. Он не указывает другой тип среды выполнения. Оба следующих объявления являются одинаковыми типами среды выполнения:

string s1 = "a string";
string? s2 = "another string";

? — это указание компилятору на ожидание нулевых значений.

Аннотация ! для выражения указывает, что вы знаете, что выражение безопасно и не должно быть равно null.

  • Эти аннотации необходимо использовать, а не System.Runtime.CompilerServices.NullableAttribute в своем коде.
  • Так как ? является заметкой, а не типом, его нельзя использовать с typeofили выражениями new.
  • Оператор ! нельзя применить к выражению переменной или группе методов.
  • Оператор ! не может быть применён слева от оператора доступа к члену, например, obj.Field!.Method().

Возможная разыменовка нулевого указателя

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

  • CS8602 - Разыменование возможно пустой ссылки.
  • CS8670 - Инициализатор объекта или коллекции неявно разыменовывает член, который, возможно, является null.

Следующий код демонстрирует один пример каждого из предыдущих предупреждений:

class Container
{
    public List<string>? States { get; set; }
}

internal void PossibleDereferenceNullExamples(string? message)
{
    Console.WriteLine(message.Length); // CS8602

    var c = new Container { States = { "Red", "Yellow", "Green" } }; // CS8670
}

В предыдущем примере предупреждение связано с тем, что Container, c, может иметь значение NULL для свойства States. Назначение новых состояний коллекции, которая может быть null, становится причиной предупреждения.

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

Во многих случаях эти предупреждения можно исправить, проверив, что переменная не равна NULL перед ее разыменованием. Рассмотрим следующий пример, который добавляет проверку на null перед разыменованием параметра message:

void WriteMessageLength(string? message)
{
    if (message is not null)
    {
        Console.WriteLine(message.Length);
    }
    
}

В следующем примере инициализируется резервное хранилище для States и удаляется set аксессор. Потребители класса могут изменять содержимое коллекции, а хранилище для коллекции никогда не используется null:

class Container
{
    public List<string> States { get; } = new();
}

Другие случаи, когда вы получаете эти предупреждения, могут быть ложными срабатываниями. Возможно, у вас есть частный метод служебной программы, который проверяет значение NULL. Компилятор не знает, что метод предоставляет проверку null. Рассмотрим следующий пример, использующий метод частной служебной программы: IsNotNull

public void WriteMessage(string? message)
{
    if (IsNotNull(message))
        Console.WriteLine(message.Length);
}

Компилятор предупреждает, что вы можете разыменовать null при попытке записать свойство message.Length, так как статический анализ показывает, что message может быть null. Вы знаете, что IsNotNull предоставляет проверку на null, и если возвращается true, состояние message должно быть не null. Необходимо сообщить компилятору эти факты. Одним из способов является использование оператора, игнорирующего null, !. Инструкцию можно изменить, чтобы она соответствовала WriteLine следующему коду:

Console.WriteLine(message!.Length);

Оператор прощения null делает выражение не-null, даже если оно было возможно-null без применения !. В этом примере лучше добавить атрибут в сигнатуру IsNotNull:

private static bool IsNotNull([NotNullWhen(true)] object? obj) => obj != null;

Эта конструкция System.Diagnostics.CodeAnalysis.NotNullWhenAttribute сообщает компилятору, что аргумент, используемый для параметра obj, не является null, когда вызываемый метод возвращает значение true. При возврате falseметода аргумент имеет то же состояние NULL, которое было до вызова метода.

Совет

Существует широкий набор атрибутов, которые можно использовать для описания того, как методы и свойства влияют на состояние NULL. Вы можете узнать о них в статье справочника по языку о атрибутах статического анализа с поддержкой NULL.

Исправление предупреждения для разыменовки переменной возможно-нуль включает один из трех методов:

  • Добавьте отсутствующий флажок NULL.
  • Добавьте в API атрибуты анализа null, чтобы повлиять на статический анализ нулевого состояния компилятора. Эти атрибуты сообщают компилятору, когда возвращаемое значение или аргумент после вызова метода должен быть возможно-null или не-null.
  • Примените оператор для прощения null ! к выражению, которое заставляет состояние не null.

Возможное значение NULL, назначенное ненулевой ссылке

Этот набор предупреждений оповещает вас о том, что вы присваиваете переменной, тип которой не допускает пустое значение, выражение, состояние null которого может быть NULL. Эти предупреждения:

  • Вызываемое значение CS8597 - может иметь значение NULL.
  • CS8600 - Преобразуется литерал NULL или возможное значение NULL в тип, не допускающий значение NULL.
  • Возможно присвоение ссылки, равной null. CS8601 -
  • CS8603 - Возможный возврат null-ссылки.
  • CS8604 - Возможный аргумент с пустой ссылкой для параметра.
  • CS8605 - Распаковка значения, которое может быть null.
  • CS8625 - Не удается преобразовать литерал NULL в ненулевой ссылочный тип.
  • Тип значения NULL CS8629 - может иметь значение NULL.

Компилятор выдает эти предупреждения при попытке назначить выражение, которое может иметь значение NULL переменной, которая является ненулевой. Например:

string? TryGetMessage(int id) => "";

string msg = TryGetMessage(42);  // Possible null assignment.

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

Чтобы устранить эти предупреждения, можно выполнить одно из трех действий. Один из них заключается в добавлении заметки ? , чтобы сделать переменную типом ссылок, допускающей значение NULL. Это изменение может вызвать другие предупреждения. Изменение переменной из ненулевой ссылки на ссылку, допускающую значение NULL, изменяет состояние NULL по умолчанию с ненулевого на может быть null. Статический анализ компилятора находит экземпляры, в которых вы разыменовываете переменную, , возможно, null.

Другие действия указывают компилятору, что правая часть присваивания не является NULL. Выражение справа может быть проверено на значение NULL перед назначением, как показано в следующем примере:

string notNullMsg = TryGetMessage(42) ?? "Unknown message id: 42";

В предыдущих примерах показано назначение возвращаемого значения метода. Вы аннотируете метод (или свойство), чтобы указать, когда метод возвращает значение, не являющееся null. Часто System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute указывается, что возвращаемое значение не равно NULL, если входной аргумент не имеет значения NULL. Другой альтернативой является добавление оператора null-прощения ! с правой стороны.

string msg = TryGetMessage(42)!;

Исправление предупреждения о назначении возможно-null выражения переменной , не допускающей значения NULL, включает в себя один из четырех методов:

  • Измените левую часть присваивания на тип, допускающий значение NULL. Это действие может привести к новым предупреждениям при разыменовании этой переменной.
  • Выполните проверку на null перед присвоением.
  • Аннотируйте API, который формирует правую часть операции присваивания.
  • Добавьте оператор null-forgiving в правую часть присваивания.

Ненуклимая ссылка не инициализирована

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

  • CS8618 - Переменная, не допускающая значение NULL, должна содержать ненулевое значение при выходе из конструктора. Рассмотрите возможность объявления её допускающей значение NULL.
  • Параметр CS8762 - должен иметь ненулевое значение при выходе.

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

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Ни инициализация FirstName, ни LastName не гарантируется. Если этот код новый, рассмотрите возможность изменения общедоступного интерфейса. Предыдущий пример можно обновить следующим образом:

public class Person
{
    public Person(string first, string last)
    {
        FirstName = first;
        LastName = last;
    }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Если требуется создать Person объект перед заданием имени, можно инициализировать свойства с помощью значения, отличного от NULL по умолчанию:

public class Person
{
    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
}

Другой альтернативой является преобразование этих элементов в ссылочные типы, допускающие значение NULL. Класс Person можно определить следующим образом, если null для имени должно быть разрешено:

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
}

Существующий код иногда требует других изменений, чтобы сообщить компилятору о семантике NULL для этих элементов. У него может быть несколько конструкторов, и класс имеет частный вспомогательный метод, который инициализирует один или несколько членов. Код инициализации можно переместить в один конструктор и убедиться, что все конструкторы вызывают его с общим кодом инициализации. Кроме того, можно использовать System.Diagnostics.CodeAnalysis.MemberNotNullAttribute атрибуты и System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute атрибуты. Эти атрибуты сообщают компилятору, что элемент не null после возврата метода. В приведенном ниже коде показан пример каждого метода. Класс Person использует общий конструктор, вызываемый всеми другими конструкторами. Класс Student содержит вспомогательный метод, аннотированный атрибутом System.Diagnostics.CodeAnalysis.MemberNotNullAttribute :


using System.Diagnostics.CodeAnalysis;

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

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

    public Person() : this("John", "Doe") { }
}

public class Student : Person
{
    public string Major { get; set; }

    public Student(string firstName, string lastName, string major)
        : base(firstName, lastName)
    {
        SetMajor(major);
    }

    public Student(string firstName, string lastName) :
        base(firstName, lastName)
    {
        SetMajor();
    }

    public Student()
    {
        SetMajor();
    }

    [MemberNotNull(nameof(Major))]
    private void SetMajor(string? major = default)
    {
        Major = major ?? "Undeclared";
    }
}

Наконец, можно использовать оператор прощения null, чтобы указать, что член инициализирован в другом коде. Например, рассмотрим следующие классы, представляющие модель Entity Framework Core:

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

public class TodoContext : DbContext
{
    public TodoContext(DbContextOptions<TodoContext> options)
        : base(options)
    {
    }

    public DbSet<TodoItem> TodoItems { get; set; } = null!;
}

Свойство DbSet инициализировано в null!. Это сообщает компилятору, что для свойства задано ненулевое значение. Фактически база DbContext выполняет инициализацию набора. Статический анализатор компилятора этого не обнаруживает. Дополнительные сведения о работе с ссылочными типами, допускаемыми значением NULL, и Entity Framework Core см. в статье о работе с типами ссылок, допускающих значение NULL, в EF Core.

Исправление предупреждения о неинициализации обязательного члена может быть выполнено одним из четырех методов:

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

Несоответствие в объявлении аннулируемости

Многие предупреждения указывают на несоответствие значений NULL между сигнатурами для методов, делегатов или параметров типа.

  • CS8608 - Определение null типов ссылок в типе не соответствует члену, который переопределяется.
  • CS8609 - Нулевое значение ссылочных типов в возвращаемом типе не соответствует переопределённым элементам.
  • CS8610 - Нулевость ссылочных типов для параметра типа не соответствует переопределённому члену.
  • CS8611 - Управление null-значениями ссылочных типов в параметре типа не соответствует объявлению частичного метода.
  • Значение NULL типов ссылок в типе CS8612 - не соответствует неявно реализованным элементу.
  • Значение NULL типов ссылок в возвращаемом типе CS8613 - не соответствует неявно реализованным элементу.
  • CS8614 - Нулевость ссылочных типов в типе параметра не соответствует неявно реализованным элементом.
  • Значение NULL типов ссылок в типе CS8615 - не совпадает с реализованным элементом.
  • CS8616 - Обнуляемость ссылочных типов в возвращаемом типе не соответствует реализованному члену.
  • CS8617 - Наличие значения у ссылочных типов в типе параметра не соответствует реализованному члену.
  • CS8619 - Нулевые значения ссылочных типов в значении не соответствуют целевому типу.
  • CS8620 - Аргумент нельзя использовать для параметра из-за различий в нулевой допустимости ссылочных типов.
  • Ошибка CS8621 - NULL-ность типов ссылок в возвращаемом значении не соответствует целевому делегату (возможно, из-за атрибутов nullability).
  • CS8622 - Нулевое значение ссылочных типов в типе параметра не соответствует целевому делегату (возможно, из-за атрибутов, связанных с null).
  • Аргумент CS8624 - нельзя использовать в качестве выходных данных из-за различий в допустимости значений NULL ссылочных типов.
  • CS8631 - Тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Значение NULL аргумента типа не соответствует типу ограничения.
  • Ошибка CS8633 - Нулевая допустимость в ограничениях на параметр типа метода не совпадает с ограничениями на параметр типа метода интерфейса. Рассмотрите возможность использования явной реализации интерфейса.
  • CS8634 - Тип нельзя использовать в качестве параметра типа в универсальном типе или методе. Значение NULL аргумента типа не соответствует ограничению class.
  • CS8643 - Нулевость ссылочных типов в явном указателе интерфейса не совпадает с интерфейсом, реализуемым типом.
  • CS8644 - Тип не реализует член интерфейса. Нулевость ссылочных типов в интерфейсе, реализованном базовым типом, не совпадает.
  • Элемент CS8645 - уже указан в списке интерфейсов по типу с разными значениями NULL ссылочных типов.
  • Объявления частичного метода CS8667 - имеют несогласованность null в ограничениях для параметра типа.
  • CS8714 - Тип нельзя использовать как параметр типа в универсальном типе или методе. Нулевость аргумента типа не соответствует ограничению 'notnull'.
  • Значение NULL типа возвращаемого значения CS8764 - не совпадает с переопределенным элементом (возможно, из-за атрибутов nullability).
  • CS8765 - Допускаемость значения параметра не соответствует переопределенному элементу (возможно, из-за атрибутов, связанных с допускаемостью значения NULL).
  • CS8766 - Проверка на допустимость null ссылочных типов в возвращаемом типе не соответствует неявно реализованному члену (возможно, из-за атрибутов nullability).
  • CS8767 - Нулевые значения типов ссылок в параметре не соответствуют неявно реализованному элементу (возможно, из-за атрибутов нулевости).
  • CS8768 - Null-способность ссылочных типов в возвращаемом значении не соответствует реализованному члену (возможно, из-за атрибутов Null-способности).
  • CS8769 - Наличие null в типах ссылок в параметре не соответствует реализованному элементу (возможно, это связано с атрибутами nullability).
  • CS8819 - Наличие NULL для ссылочных типов в возвращаемом типе не соответствует объявлению частичного метода.

Следующий код демонстрирует CS8764:

public class B
{
    public virtual string GetMessage(string id) => string.Empty;
}
public class D : B
{
    public override string? GetMessage(string? id) => default;
}

В предыдущем примере показан метод virtual в базовом классе и override с разной допустимостью NULL. Базовый класс возвращает строку, не допускающую NULL, но производный класс возвращает строку, допускающую NULL. Если string и string? поменять местами, это будет разрешено, так как производный класс является более строгим. Аналогичным образом объявления параметров должны совпадать. Параметры в методе переопределения могут принимать null, даже если базовый класс не допускает null.

Другие ситуации могут создавать эти предупреждения. У вас есть несоответствие в объявлении метода интерфейса и реализации этого метода. Или тип делегата и выражение для этого делегата отличаются. Параметр типа и аргумент типа отличаются по наличию значения null.

Чтобы устранить эти предупреждения, обновите соответствующее объявление.

Код не соответствует объявлению атрибутов

В предыдущих разделах описано, как использовать атрибуты для статического анализа, допускающего значение NULL, для информирования компилятора о семантике NULL кода. Компилятор предупреждает вас, если код не соответствует обещаниям этого атрибута:

  • CS8607 - Возможное значение NULL не может быть использовано для типа, помеченного [NotNull] или [DisallowNull]
  • CS8763 - Метод, помеченный [DoesNotReturn], не должен возвращать значение.
  • CS8770 - Метод не имеет аннотации [DoesNotReturn] для совпадения с реализованным или переопределенным элементом.
  • Элемент CS8774 - должен иметь ненулевое значение при выходе.
  • Элемент CS8775 - должен иметь ненулевое значение при выходе.
  • Член CS8776 - нельзя использовать в этом атрибуте.
  • Параметр CS8777 - должен иметь ненулевое значение при выходе.
  • Параметр CS8824 - должен иметь ненулевое значение при выходе, так как параметр не имеет значения NULL.
  • CS8825 - Возвращаемое значение должно быть не null, так как параметр является ненулевым.

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

public bool TryGetMessage(int id, [NotNullWhen(true)] out string? message)
{
    message = null;
    return true;

}

Компилятор выдает предупреждение, так как message параметр назначается nullи метод возвращается true. Атрибут NotNullWhen указывает, что не должно произойти.

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

Исчерпывающее выражение переключателя

Выражения коммутатора должны быть исчерпывающими, что означает, что все входные значения должны обрабатываться. Даже для ссылочных типов, не допускающих значение NULL, необходимо учитывать значение null. Компилятор выдает предупреждения, когда значение NULL не обрабатывается:

  • CS8655 - Выражение коммутатора не обрабатывает некоторые входные данные NULL (это не является исчерпывающим).
  • CS8847 - Выражение коммутатора не обрабатывает некоторые входные данные NULL (это не является исчерпывающим). Однако шаблон с предложением "when" может успешно соответствовать этому значению.

В следующем примере кода демонстрируется следующее условие:

int AsScale(string status) =>
    status switch
    {
        "Red" => 0,
        "Yellow" => 5,
        "Green" => 10,
        { } => -1
    };

Входное выражение — это string, а не string?. Компилятор по-прежнему создает это предупреждение. Шаблон { } обрабатывает все ненулевое значения, но не соответствует null. Чтобы устранить эти ошибки, можно добавить явный null случай или заменить { } на _ (шаблон отбрасывания). Шаблон игнорирования совпадает с null вдобавок к другим значениям.