Как избежать разыменования возможной нулевой ссылки?

(Использование ASP.NET Core 7 и VS2022)

У меня есть служебная функция, которую я заимствовал из старого проекта .NET:

Оригинал выглядел так:

public static string WriteString(object str)
{
    if (str == null)
        return "";
    else
        return str.ToString().Trim();
}

Я преобразовал это в это:

public static string WriteString(object str)
{
    object s = str ?? "";
    return s.ToString().Trim();
}

Но я все еще получаю предупреждение «Разыменование возможно нулевой ссылки». Я что-то пропустил? Мои переменные не могут быть нулевыми, потому что я использую оператор объединения нулевых значений. Так что же беспокоит VS?

Проблема в том, что Object.ToString() возвращает string?

phuzi 04.07.2024 13:00

@phuzi, что неудобно, поскольку «Ваше переопределение ToString() не должно возвращать пустую или нулевую строку».

MakePeaceGreatAgain 04.07.2024 13:03

Я задала вопрос, связанный с этим. Меня не совсем убедили причины, по которым ToString() позволяет возвращать ноль...

Matthew Watson 04.07.2024 13:24
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
113
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

В Visual Studio, если вы перейдете к определению класса Object, вы увидите подпись .ToString().

    //
    // Summary:
    //     Returns a string that represents the current object.
    //
    // Returns:
    //     A string that represents the current object.
    public virtual string? ToString();

string? приводит к тому, что str.ToString() оценивается как string?, а .Trim() может работать только с необнуляемым string. Технически вы никогда не получите ошибку, но вы можете выполнить дополнительную проверку на нулевое значение для str.ToString() != null

или вы можете сделать str.ToString()!.Trim() просто чтобы удовлетворить компилятор

Проекты .NET Framework не выдают это предупреждение, поскольку подпись для .ToString() отличается.

public virtual string ToString() => this.GetType().ToString();

Вы предполагаете, что ToString() всегда будет возвращать здесь ненулевое строковое значение и играете с NullReferenceExce[tion. Лучше писать код защитно и проверять значение null на каждом этапе.

phuzi 04.07.2024 13:16

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

Yehor Androsov 04.07.2024 13:19

Странно, но я получаю предупреждение «Возможное исключение NullReferenceException» в Rider.

phuzi 04.07.2024 13:37

Хм, я тестировал проект .NET Framework с нулевыми значениями — предупреждения, но если я вставлю этот код в .net 7 с включенным нулевым значением — я получаю предупреждение, как в Visual Studio.

Yehor Androsov 04.07.2024 13:42

Ах, сигнатура метода для .NET Framework другая... public virtual string ToString ();

phuzi 04.07.2024 13:43

ок, спасибо, исправлю свой ответ

Yehor Androsov 04.07.2024 13:44

Вы можете сделать следующее:

public static string WriteString(object str)
{
    return s?.ToString().Trim() ?? "";
}

Если какой-либо из возможных объектов в вашем проекте может возвращать значение NULL в результате функции ToString, вы также можете добавить проверку для этого, чтобы избежать вызова Trim() для объекта NULL:

public static string WriteString(object str)
{
    return s?.ToString()?.Trim() ?? "";
}

Что s и ToString() ещё могут вернуться null!

phuzi 04.07.2024 13:03

@phuzi, ты прав, я понял это и адаптировал свой ответ.

Lex W. 04.07.2024 13:07
Ответ принят как подходящий

Как утверждали другие, Object.ToString() возвращает string?, который может возвращать нулевое значение.

Вот документация: Object.ToString

И фактическая реализация:

/// <summary>Returns a string that represents the current object.</summary>
/// <returns>A string that represents the current object.</returns>
public virtual string? ToString()
{
    // The default for an object is to return the fully qualified name of the class.
    return GetType().ToString();
}

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

public static string WriteString(object str) =>
    str?.ToString()?.Trim() ?? "";
Предостережение относительно .NET Framework

Интересно, что сигнатура метода .NET Framework `Object.Tostring() отличается

public virtual string ToString ();

Если бы вы ориентировались на .NET Framework, ваш код вообще не выдал бы никаких предупреждений.

Спасибо. Я знал, что в .NET он не выдает предупреждений, потому что я использовал его там без проблем. Но ваше решение отлично работает.

Lisa 04.07.2024 16:53

И наконец (возможно) создайте расширение и используйте лучшее имя:

public static string ToStringTrimmedOrEmpty(this object obj) 
      => obj?.ToString()?.Trim() ?? string.Empty;
    

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

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

Другие вопросы по теме