Для чего нужен ложный оператор в C #? - PullRequest
107 голосов
/ 29 августа 2008

В C # есть два странных оператора:

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

Допустим, у меня есть следующий класс:

    public class MyType
    {
        public readonly int Value;

        public MyType(int value)
        {
            Value = value;
        }

        public static bool operator true (MyType mt)
        {
            return  mt.Value > 0;
        }

        public static bool operator false (MyType mt)
        {
            return  mt.Value < 0;
        }

    }

Так что я могу написать следующий код:

    MyType mTrue = new MyType(100);
    MyType mFalse = new MyType(-100);
    MyType mDontKnow = new MyType(0);

    if (mTrue)
    {
         // Do something.
    }

    while (mFalse)
    {
        // Do something else.
    }

    do
    {
        // Another code comes here.
    } while (mDontKnow)

Однако для всех приведенных выше примеров выполняется только оператор true. Так для чего хорош ложный оператор в C #?

Примечание: другие примеры можно найти здесь , здесь и здесь .

Ответы [ 5 ]

65 голосов
/ 29 августа 2008

Вы можете использовать его для переопределения операторов && и ||.

Операторы && и || не могут быть переопределены, но если вы переопределяете |, &, true и false абсолютно правильным образом, компилятор вызовет | и & когда вы пишете || и &&.

Например, посмотрите на этот код (из http://ayende.com/blog/1574/nhibernate-criteria-api-operator-overloading - где я узнал об этой уловке; архивная версия от @BiggsTRC):

public static AbstractCriterion operator &(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new AndExpression(lhs, rhs);
}

public static AbstractCriterion operator |(AbstractCriterion lhs, AbstractCriterion rhs)
{
       return new OrExpression(lhs, rhs);
}

public static bool operator false(AbstractCriterion criteria)
{
       return false;
}
public static bool operator true(AbstractCriterion criteria)
{
       return false;
}

Это, очевидно, побочный эффект, а не тот, для которого он предназначен, но он полезен.

25 голосов
/ 29 августа 2008

Shog9 и Nir: спасибо за ваши ответы. Эти ответы указали мне на статью Стива Эйхерта , и она указала мне на msdn :

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

14 голосов
/ 29 августа 2008

На странице, на которую вы ссылаетесь http://msdn.microsoft.com/en-us/library/6x6y6z4d.aspx, написано, для чего они были, и это был способ обработки значений типа Nullable Bools до введения типов значений NULL.

Я бы предположил, что в настоящее время они хороши для того же рода вещей, что и ArrayList - то есть абсолютно ничего.

7 голосов
/ 29 августа 2008

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

if ( mFalse && mTrue) 
{
   // ... something
}

mFalse.false() вызывается, и после возврата true выражение сводится к вызову mFalse.true () '(который затем должен вернуть false, иначе все станет странно).

Обратите внимание, что для компиляции этого выражения необходимо реализовать оператор &, поскольку он используется, если mFalse.false() возвращает false.

3 голосов
/ 29 августа 2008

Как видно из статьи MSDN, на которую вы ссылались, она была предоставлена ​​для допускающих обнуляемый логический тип до того, как тип Nullable (т.е. int ?, bool? И т. Д.) Был введен в язык в C # 2. Таким образом, вы бы сохранили внутреннее значение, указывающее, является ли значение истинным, ложным или нулевым, т.е. в вашем примере> 0 для истинного, <0 для ложного и == 0 для нулевого, а затем вы получите нулевую семантику в стиле SQL. Вы также должны будете реализовать метод или свойство .IsNull, чтобы можно было явно проверить недействительность. </p>

По сравнению с SQL, представьте таблицу Table с 3 строками со значением Foo, установленным в значение true, 3 строками со значением Foo, установленным в значение false, и 3 строками со значением Foo, установленным в значение null.

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE
6

Чтобы сосчитать все строки, вам нужно сделать следующее: -

SELECT COUNT(*) FROM Table WHERE Foo = TRUE OR Foo = FALSE OR Foo IS NULL
9

Этот синтаксис "IS NULL" будет иметь эквивалентный код в вашем классе как .IsNull ().

LINQ делает сравнение с C # еще более понятным: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s
                 select s).Count();

Представляя, что MyTypeEnumberable имеет точно такое же содержимое базы данных, то есть 3 значения равны true, 3 значения равны false и 3 значения равны нулю. В этом случае totalCount будет оцениваться до 6 в этом случае. Однако, если мы переписали код как: -

int totalCount = (from s in MyTypeEnumerable
                 where s || !s || s.IsNull()
                 select s).Count();

Тогда totalCount оценивается в 9.

Пример DBNull, приведенный в связанной статье MSDN об операторе false, демонстрирует класс в BCL, который имеет такое точное поведение.

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

Обновление: Я только что заметил, что вам нужно вручную переопределить логические операторы!, || и && для правильной работы. Я полагаю, что ложный оператор подает эти логические операторы, то есть указывает на правду, ложь или «иное». Как отмечено в другом комментарии! X не сработает; Вы должны перегрузить! Weirdness!

...