Имеет ли оператор «true» в c# только два места, которые можно использовать? - PullRequest
6 голосов
/ 13 марта 2020

c# позволяет переопределить «оператор истина» и «оператор ложь» для класса:

class Foo
{
   bool Thing;

   Foo(bool thing)
   {
      Thing = thing;
   }

   public static bool operator true(Foo foo) => foo.Thing;
   public static bool operator false(Foo foo) => !foo.Thing;
}

, и это работает. Вы можете сказать

Foo foo = new Foo(true);
if (foo)
   Stuff();
string s = foo ? "yes" : "no";

Но вы не можете сказать

Foo foo = new Foo(true);
bool boo = true;
if (boo && foo)
   Stuff();
if (boo & foo)
   Stuff();
if (boo & (foo == true))
   Stuff();
if (boo & ((bool)foo))
   Stuff();
Foo foo2 = new Foo(true);
if (foo && foo2)
   Stuff();
if (foo & foo2)
   Stuff();
if (foo == boo)
   Stuff();
if (foo != boo)
   Stuff();
bool boo2 = foo;

В каждом случае компилятор жалуется.

Использует ли оператор c# компилятор "true "и" оператор ложь "где угодно, за исключением тех очень специфических c синтаксисов?

РЕДАКТИРОВАТЬ

Я нашел еще одно место, где работают" оператор истина "и" оператор ложь ". Если вы определите «оператор &», который возвращает Foo в дополнение к операторам «истина» и «ложь», компилятор примет выражение «foo1 && foo2» и сделает вид, что вы написали «foo1 & foo2», и вызовет переопределенный оператор. Другими словами, существование «operator true» и «operator false» изменяет поведение компилятора , даже если он никогда не вызывает эти операторы .

Ответы [ 2 ]

7 голосов
/ 13 марта 2020

Имеет ли оператор «true» в c# только два места, которые можно использовать?

Не совсем. Вы можете найти в C# Спецификации языка слово «оператор истина» (я так и сделал) и посмотреть, что он делает. Разделы 7.12.2 , 7.14 , 7.20 упоминают об этом. В сущности 7.14 - это троичный оператор, о котором вы уже знаете, но в 7.20 говорится, что

A boolean-expression - это выражение, которое дает результат типа bool; либо непосредственно, либо через применение оператора true в определенных контекстах, как указано в следующем:

Управляющее условное выражение if-statement (§8.7.1), while-statement (§8.8.1) do-statement (§8.8.2) или for-statement (§8.8.3) - это boolean-expression.

Таким образом, не только в выражении if, но и в a while, do, for.

В 7.12.2 говорится:

Когда операнды && или || типов, которые объявляют применимый пользовательский оператор & или оператор |, оба из следующих условий должны быть истинными, где T - тип, в котором объявлен выбранный оператор:

  • Тип возвращаемого значения и тип каждого параметра выбранного оператора должны быть T. Другими словами, оператор должен вычислять логическое И или логическое ИЛИ двух операндов типа T и возвращать результат типа T.
  • T должен содержать объявления оператора true и оператор false.

Так что && можно использовать для вашего пользовательского типа, если вы также объявите &.


РЕДАКТИРОВАТЬ:

Только что нашел эту ссылку , что очень ясно подводит итог.


Другими словами, существование " operator true "и" operator false "изменяют поведение компилятора, даже если он никогда не вызывает эти операторы.

Он вызывает эти операторы. Согласно языку spe c 7.12.2:

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

По сути, поскольку && является коротким замыканием, он должен знать, является ли один из его операндов ложным, используя оператор false.

, так почему же разработчики языка создали "оператор" true "и" operator false "?

Это довольно хорошо объяснено здесь , я думаю:

Оператор true возвращает значение bool true, чтобы указать, что его операнд определенно истинен. Оператор false возвращает значение bool true, указывающее, что его операнд определенно является ложным.

Это в основном для ситуаций, когда вы хотите, чтобы ваш пользовательский тип имел значение true / falsey. Тип LaunchStatus в той же ссылке и тип DBBool здесь являются хорошими примерами этого.

3 голосов
/ 13 марта 2020

Если вы хотите, чтобы все эти условные операторы компилировались, вам нужно реализовать больше операторов в дополнение к true и false. Вы можете заставить их всех работать с этой реализацией:

public class Foo
{
    bool Thing;

    public Foo(bool thing)
    {
        Thing = thing;
    }

    public static bool operator true(Foo foo) => foo;
    public static bool operator false(Foo foo) => !foo;
    public static implicit operator bool(Foo foo) => foo?.Thing ?? false;
    public static implicit operator Foo(bool b) => new Foo(b);
    public static Foo operator &(Foo left, Foo right) => (left?.Thing & right?.Thing) ?? false;
    public static Foo operator |(Foo left, Foo right) => (left?.Thing | right?.Thing) ?? false;
}

Теперь, если вы удалите операторы true и false, вы увидите, что операции короткого замыкания if(boo && foo) и if(foo && foo2) больше не будет компилироваться. Как писал @Sweeper в своем ответе, эти операторы необходимы для компиляции короткозамкнутых выражений.

...