Перегрузка true и false, перегрузка false, похоже, никогда не используется

В книге C#12 In a Nutshell (стр. 259, глава «Перегрузка true и false») они предоставляют нам этот пример, чтобы проиллюстрировать, как перегружать операторы true и false.

SqlBoolean a = SqlBoolean.Null;
if (a)
    Console.WriteLine ("True");
else if (!a)
    Console.WriteLine ("False");
else
    Console.WriteLine ("Null");

public struct SqlBoolean
{
    public static bool operator true (SqlBoolean x)
    {
        return  x.m_value == True.m_value;
    }

    public static bool operator false(SqlBoolean x)
    {
        return x.m_value == False.m_value;
    }

    public static SqlBoolean operator ! (SqlBoolean x)
    {
        if (x.m_value == Null.m_value) return Null;
        if (x.m_value == False.m_value) return True;
        return False;
    }

    public static readonly SqlBoolean Null = new SqlBoolean (0);
    public static readonly SqlBoolean False = new SqlBoolean (1);
    public static readonly SqlBoolean True = new SqlBoolean (2);

    SqlBoolean (byte value) { m_value = value; }
    byte m_value;
}

Я пытаюсь понять, когда когда-либо вызывается перегрузка false, и, насколько я понимаю (и подтверждаю это игрой с отладчиком), кажется, что она никогда не вызывается. почему тогда перегрузка false может быть полезна? Поскольку мы всегда используем только while (a) или while (!a) и т. д., разве перегрузки true и ! не будет достаточно?

Кроме того, обратите внимание, что основной причиной реализации перегрузки операторов true и false действительно была обработка логики с тремя состояниями (например, логические значения SQL, которые могут иметь значение NULL). Теперь это лучше представлено с помощью типа bool, допускающего значение NULL, что делает перегрузка операторов true/false в наши дни крайне необычна.

Matthew Watson 03.09.2024 10:01

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

FluidMechanics Potential Flows 03.09.2024 10:03
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
2
82
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ложный оператор вступит в действие, когда возникнет короткое замыкание - с оператором &&, когда, если первое выражение не удалось, мы можем игнорировать второе.

В такой ситуации будет вызван ложный оператор, см. пример:

// Need to define this operator in order to leverage short circuiting with &&,
// it will be analogical with ||
public static SqlBoolean operator &(SqlBoolean left, SqlBoolean right)
{
    // Implement appropriately, this is just example
    return True;
}

И далее тест:

var shortCircuitAnd = a && a;
Ответ принят как подходящий

В стандарте C# есть такое примечание:

Примечание. Хотя true и false не используются в выражениях явно (и, следовательно, не включены в таблицу приоритетов в §12.4.2), они считаются операторами, поскольку вызываются в нескольких контекстах выражений: логических выражениях (§12.24) и выражениях. с использованием условных (§12.18) и условных логических операторов (§12.14). конечная заметка

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

Операция x && y оценивается как T.false(x) ? x : T.&(x, y), где T.false(x) — это вызов operator false, объявленный в T, а T.&(x, y) — это вызов выбранного operator &. Другими словами, x сначала оценивается, а operator false вызывается для результата, чтобы определить, является ли x определенно ложным. Тогда, если x определенно ложно, результатом операции будет значение, ранее вычисленное для x. В противном случае оценивается y, и выбранный operator & вызывается для значения, ранее вычисленного для x, и значения, вычисленного для y, для получения результата операции.

Вот небольшой тестовый код, показывающий разное время использования операторов:

LoggingBoolean t = new LoggingBoolean(true);
LoggingBoolean f = new LoggingBoolean(false);

Console.WriteLine("Boolean expression");
if (t)
{
    Console.WriteLine("In true body");
}

if (f)
{
    Console.WriteLine("In false body");
}

Console.WriteLine("Conditional operator");

Console.WriteLine(t ? "true branch" : "false branch");
Console.WriteLine(f ? "true branch" : "false branch");

Console.WriteLine("Conditional && logic");
Console.WriteLine(t && t);
Console.WriteLine(t && f);
Console.WriteLine(f && t);
Console.WriteLine(f && f);

Console.WriteLine("Conditional || logic");
Console.WriteLine(t || t);
Console.WriteLine(t || f);
Console.WriteLine(f || t);
Console.WriteLine(f || f);

internal struct LoggingBoolean
{
    public bool Value { get; }

    public LoggingBoolean(bool value) => Value = value;

    public static bool operator false(LoggingBoolean x)
    {
        Console.WriteLine("false operator called");
        return !x.Value;
    }

    public static bool operator true(LoggingBoolean x)
    {
        Console.WriteLine("true operator called");
        return x.Value;
    }

    public static LoggingBoolean operator &(LoggingBoolean x, LoggingBoolean y) =>
        new LoggingBoolean(x.Value && y.Value);

    public static LoggingBoolean operator |(LoggingBoolean x, LoggingBoolean y) =>
        new LoggingBoolean(x.Value || y.Value);

    public override string ToString() => $"LoggingBoolean({Value})";
}

Выход:

Boolean expression
true operator called
In true body
true operator called
Conditional operator
true operator called
true branch
true operator called
false branch
Conditional && logic
false operator called
LoggingBoolean(True)
false operator called
LoggingBoolean(False)
false operator called
LoggingBoolean(False)
false operator called
LoggingBoolean(False)
Conditional || logic
true operator called
LoggingBoolean(True)
true operator called
LoggingBoolean(True)
true operator called
LoggingBoolean(True)
true operator called
LoggingBoolean(False)

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