Поток программы условия на том, является ли `двойник?` нулевым

В C# к типу можно добавить вопросительный знак, чтобы указать, что он может содержать либо значение типа, либо возвращать null:

double? MySqrt(double a)
{
    return (a > 0.0) ? Math.Sqrt(a) : null;
}

Console.WriteLine(MySqrt(4.5));     // 2.1213203435596424
Console.WriteLine(MySqrt(-4.5));    // a blank line

Теперь, если я хочу обусловить присвоение переменной результата этой функции, я могу использовать оператор ??, например.

double b = MySqrt(-2.0) ?? 0.0;
Console.WriteLine(b);     // 0

Но без переопределения MySqrt, как я могу управлять более широким программным потоком (а не только присваиванием одной переменной) в зависимости от того, вернуло ли MySqrtnull?

Например, следующее приводит к ошибке компилятора:

void DrawSquareWithArea(double area)
{
    double sideLength = MySqrt(area);
    if (sideLength != null)
    {
        // Draw a square on the screen
        DrawSquare(sideLength);
    }
    else
    {
        // Display some visual feedback indicating that input was invalid
        DisplayErrorFeedback();
    }
}
// error CS0266: Cannot implicitly convert type 'double?' to 'double'. An explicit conversion exists (are you missing a cast?)

Обратите внимание, что функция DrawSquare() требует аргумента double, поэтому изменение sideLength на double? является еще одной ошибкой компилятора.

Ошибка очень ясна — замените double sideLength либо на var sideLength, либо на double? sideLength.

Zohar Peled 10.01.2023 14:45

Это тоже ошибка компилятора, потому что для функции DrawSquare требуется двойник.

Max 10.01.2023 14:46
DrawSquare(sideLength.Value); возможно?
Matthew Watson 10.01.2023 14:48

Если вы рассматриваете double? как коробку, внутри которой либо double, либо ничего нет, вы можете извлечь double из этой коробки, используя sideLength.Value (но если там ничего не было, будет выдано исключение, хотя в этом случае вы сначала проверили, что там что-то есть).

Evk 10.01.2023 14:49
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
83
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Используя правильный тип (Nullable<double> он же double?). Доступ к ненулевому значению можно получить с помощью свойства Value (которое здесь имеет тип double):

void DrawSquareWithArea(double area)
{
    double? sideLength = MySqrt(area);
    if (sideLength != null) // or: if (sideLength.HasValue)
    {
        // Draw a square on the screen
        DrawSquare(sideLength.Value);
    }
    else
    {
        // Display some visual feedback indicating that input was invalid
        DisplayErrorFeedback();
    }
}

Или попросите компилятор вывести тип:

var sideLength = MySqrt(area);

Да, вопрос был отредактирован, чтобы уточнить комментарий. Value возвращает необработанное значение (т.е. double)

knittl 10.01.2023 15:07

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

TJ Rockefeller 10.01.2023 15:36

Вы не можете явно преобразовать double? в double. Либо проверьте null, либо используйте .Value:

void DrawSquareWithArea(double area)
{
    double? sideLength = MySqrt(area);
    if (sideLength is not null)
    {
        // Draw a square on the screen
        DrawSquare(sideLength.Value); // sideLength.Value is double
    }
    //...
}

или используйте сопоставление шаблонов с шаблоном объявления:

void DrawSquareWithArea(double area)
{
    if (MySqrt(area) is {} len) // checks for null and assigns variable of double type
    {
        // Draw a square on the screen
        DrawSquare(len);
    }
    //...
}

или :

void DrawSquareWithArea(double area)
{
    if (MySqrt(area) is double len) // checks for null and assigns variable of double type
    {
        // Draw a square on the screen
        DrawSquare(len);
    }
    //...
}

Читать далее:

Другие ответы в порядке. Однако я хотел бы добавить еще один подход, который может быть весьма удобным и (с моей точки зрения) может быть даже лучше, чем использование null в качестве возвращаемого типа. Если ваш метод вызывается с недопустимым значением, почему бы просто не выдать исключение? В вызывающем методе обработайте выброшенное исключение. Минимальный рабочий пример может выглядеть следующим образом.

class Program
{
    static void Main(string[] args)
    {
        try{
            MySqrt(-5);
        } catch(Exception e) {
            Console.WriteLine(e.Message);
        }
    }
    static double MySqrt(double a)
    {
        if (a > 0.0) return Math.Sqrt(a);
        throw new ArithmeticException("Can not calculate square root of negative value!");
    }
}

Я не знаю о C#, но в других языках, которые я использую, блоги try/except обычно используются для отладки во время разработки и обычно не включаются в производственный код. Конвенция здесь другая?

Max 10.01.2023 15:27

Почти все более-менее сложные приложения могут столкнуться с исключением, о котором можно не думать во время разработки (как в вашем случае). Поэтому всегда полезно перехватывать исключения в какой-то момент (на максимально возможном уровне) в вашем коде и правильно их обрабатывать. Преимущество в том, что вы можете точно увидеть, где возникла проблема (если вы передадите объект исключения и зарегистрируете его). Но это просто предпочтения. Я просто хотел добавить другой подход :)

Aaron 10.01.2023 15:40

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