логические выражения, почему просто два термина? - PullRequest
4 голосов
/ 09 июня 2010

Учитывая, что можно написать

a = b = c = 2;

Было бы неплохо вместо

bool allTwo = a == 2 && b == 2 && c == 2;

вместо этого написать

bool allTwo = a == b == c == 2;

Но я могут, так как a == b вычисляется как логическое значение, которое не может тогда быть сравнено с целым числом.

Есть ли причина языковой конструкции, которая была реализована таким образом?

Ответы [ 8 ]

8 голосов
/ 09 июня 2010

Тип выражения a == b является логическим, поэтому вам придется либо нарушить правило, согласно которому выражение означает одно и то же, независимо от его контекста, либо иметь n-арные операторы ==, чтобы a == b == c анализировался как (== a b c), а не (== (== a b) c). Это означает, что вам нужно иметь (a == b) == c для сравнения логического c с результатом (a == b), что нормально, но не в простом грамматическом стиле С, который в C # является традицией.

5 голосов
/ 09 июня 2010

Ну, выражение c == 2 вернуло бы true, так что тогда b сравнивалось бы с true, а не 2.

Редактировать: Скорее всего, это было реализовано так, как этокак языки стиля C обрабатывают логические выражения.Им пришлось бы сделать специальное исключение для нескольких терминов и реализовать его по-разному, тогда как с помощью оператора присваивания это более просто: самое правое выражение оценивает значение, которое логически может быть применено к следующему выражению в цепочке.Кажется, дизайнеры выбрали простой подход.

3 голосов
/ 09 июня 2010

С моей точки зрения, это вопрос ясности. Если бы решение было за мной, я бы подумал, как добавление такой языковой функции может добавить слишком много двусмысленности в отношении того, как оцениваются сложные выражения. Отличается ли a == b == c от (a == b) == c в определенных ситуациях? Что если я действительно хочу сравнить c с логическим результатом a == b, а не сравнивать c с b? В большинстве случаев компилятор, вероятно, может выяснить правильное сравнение, но если c неявно преобразуется в bool, хотя и маловероятно, то это невозможно определить.

Так что лично я не уверен, что это стоит хлопот. Хотя синтаксически это может выглядеть не очень красиво, вы можете создать свою собственную служебную функцию для сравнения равенства нескольких объектов, например, ниже:

    public static bool Equals(this object x, params object[] y)
    {
        for (int i = 0; i < y.Length; i++)
        {
            if (!object.Equals(x, y[i]))
                return false;
        }
        return true;
    }

Тогда вы можете использовать это так:

        if (a.Equals(b, c, d, e, f, g))
        {
            // ...
        }
2 голосов
/ 09 июня 2010

Я не могу найти цитату, но я думаю, что это был Эрик Липперт (?), Который выразил это лучше всего: не реализовывать функцию бесплатно.См. Также http://blog.ryjones.org/2005/07/12/product-development/ и http://blog.ryjones.org/2005/07/12/product-development/

У них много возможностей для реализации, и я не могу представить что-то нестандартное с сомнительным значением, которое будет иметь высокий приоритет.Я не говорю, что это не ценно, но это может привести к путанице, вероятно, не будет использоваться очень часто, и т. Д. Я думаю, что у a1ex07 тоже есть хороший момент.Это должен быть пользовательский случай, поскольку он больше не может обрабатываться в общем случае (== всегда возвращает логическое значение и т. Д.)

Вы можете сделать то же самое сейчас с LINQ, но синтаксис немногоболее сложный и требует выделения какого-либо массива:

bool allTwo = new int[] { a, b, c }.All(i => i == 2);

Вы можете сделать это задом наперед и проверить, есть ли! = 2:

bool allNotTwo = new int[] { a, b, c }.Any(i => i != 2);

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

Редактировать: Вот еще один момент: Есть ли в C # слишком много языковых функций?

что-то новое должно быть очень полезным, чтобы сделать это на языке

1 голос
/ 09 июня 2010

Игнорирование возвращаемых значений, это также связано с оператором ассоциативности .

Операторы присваивания являются ассоциативными справа. То есть правая часть оператора присваивания вычисляется первой. Вот почему вы можете сделать a = b = c = 2 и им всем присвоить значение 2. В противном случае вы получите a со старым значением b и b со старым значением c.

Большинство других операторов являются левоассоциативными, особенно логические операторы короткого замыкания (&& и ||). То есть a == b или a && b сначала оценивают a.

Можно утверждать, что == может быть правоассоциативным ... за исключением того, что в .NET это невозможно, потому что для объектов a == b (если не переопределено) преобразуется в a.Equals(b) (или это *) 1022 * ... никогда не помню).

1 голос
/ 09 июня 2010

Я думаю, что ваш вопрос несколько ухудшился с вашей точки зрения.

В a = b = c = 2 нет ничего волшебного, чтобы предположить, что a == b == c == 2 должен работать так, как вы хотите - на самом деле больше, наоборот -

Оператор присваивания определен только для 2 операндов и возвращает установленное значение. Строка из них просто передает значение от каждого оператора следующему:

1: a = (b = (c = 2));
2: a = (b = (2));
3: a = (2);

То же самое относится и к a == b == c == 2:

1: bool allTwo = (a == (b == (c == 2)));
2: bool allTwo = (a == (b == ([Boolean])));
3: bool allTwo = (a == ([Boolean]));
4: bool allTwo = ([Boolean]);

Итак, техническая причина заключается в том, что C# не содержит определения для специальной обработки строки операторов.

Что касается дизайна и реализации языка, причина, вероятно, заключалась бы в том, чтобы предотвратить двусмысленность и дополнительную сложность. Хотя вы, возможно, захотите, чтобы a == b == c == 2 был определен как оператор , все равно равный , на следующей строке он вполне может понадобиться для того, чтобы он действовал так, как в настоящее время реализовано. Как следует различать поведение? И действительно ли это стоило бы усилий для реализации?

Или a == 2 && b == 2 действительно так плохо? ;)

1 голос
/ 09 июня 2010

Чтобы сделать то, что вы хотите, operator == должен вернуть объект. В этом случае у нас будет другая проблема - теперь нам нужно неявное преобразование любого объекта в логическое значение. Такое преобразование также создаст дополнительные проблемы.

0 голосов
/ 09 июня 2010

Не прямой ответ на ваш вопрос, но как насчет:

bool allTwo = a & b & c == 2;

РЕДАКТИРОВАТЬ: Как говорит Пит, это не сработает.Как это?

bool allEqual(params int[] inputs)
{
    int lastval = inputs[0];
    for (int i = 1; i < inputs.length; i++)
    {
        if (lastval != inputs[i])
            return false;

        lastval = inputs[i];
    }

    return true;
}

Объявите это один раз, используйте его, когда хотите, с разделенным запятыми списком целых чисел для сравнения.(Возможно, есть даже более простая функция для этого, но неважно.)

bool allTwo = a == b && b == c && c == 2; // prefer this format over a == 2 && b == 2 && c == 2, personally

против

bool allTwo = allEqual(a, b, c, 2);

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

...