Для чего нужен фальшивый оператор в С#?

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

Если я понимаю это право, эти операторы могут использоваться в типах, которые я хочу использовать вместо булевского выражения, и где я не хочу предоставлять неявное преобразование в 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)

Однако для всех приведенных выше примеров выполняется только истинный оператор. Итак, для чего нужен фальшивый оператор в С#?

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

Ответ 1

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

Операторы && и || не могут быть переопределены, но если вы переопределите |, &, 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;
}

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Сравнивая с SQL, представьте таблицу Table с тремя строками со значением 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 делает сравнение с С# еще более ясным: -

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 с ложным оператором, демонстрирует класс в BCL, который имеет это точное поведение.

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

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