ИЛИ оператор в C # - PullRequest
       70

ИЛИ оператор в C #

4 голосов
/ 05 мая 2009

Могу ли я достичь

if (a == "b" || "c")

вместо

if (a == "b" || a== "c")

Ответы [ 7 ]

16 голосов
/ 05 мая 2009

Ну, самое близкое, что вы можете получить:

switch (a) {
   case "b":
   case "c":
      // variable a is either "b" or "c"
      break;
}
14 голосов
/ 05 мая 2009

Нет, вы можете сделать:

if (new[] { "b", "c" }.Contains(a))

если у вас есть расширения LINQ , но это вряд ли улучшение.


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

Результаты сначала:

||, not found: 26 ms
||, found: 8 ms
array.Contains, not found: 1407 ms
array.Contains, found: 1388 ms
array.Contains, inline array, not found: 1456 ms
array.Contains, inline array, found: 1427 ms
switch-statement, not interned, not found: 26 ms
switch-statement, not interned, found: 14 ms
switch-statement, interned, not found: 25 ms
switch-statement, interned, found: 8 ms

Весь код был выполнен дважды, и только передать номер. 2 было сообщено, чтобы убрать издержки JITting из уравнения. Оба прохода выполняли каждый тип проверки миллион раз и выполняли его, когда элемент для поиска был одним из элементов, в котором он был найден (т. Е. Оператор if выполнил бы его блок), и один раз, когда элемент не был найден. (блок не будет выполнен). Время каждого сообщается. Я тестировал как предварительно собранный массив, так и тот, который создается каждый раз, в этой части я не уверен, сколько компилятор выводит и оптимизирует, здесь может быть недостаток.

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

Пожалуйста, возьмите код и исправьте его (или прокомментируйте), если возникнут проблемы.

А вот исходный код, довольно длинный:

using System;
using System.Linq;
using System.Diagnostics;
namespace StackOverflow826081
{
    class Program
    {
        private const Int32 ITERATIONS = 1000000;
        static void Main()
        {
            String a;
            String[] ops = CreateArray();
            Int32 count;
            Stopwatch sw = new Stopwatch();
            Int32 pass = 0;
            Action<String, Int32> report = delegate(String title, Int32 i)
            {
                if (pass == 2)
                    Console.Out.WriteLine(title + ": " + sw.ElapsedMilliseconds + " ms");
            };

            for (pass = 1; pass <= 2; pass++)
            {
                #region || operator

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (a == "b" || a == "c")
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("||, found", count);
                sw.Reset();

                #endregion

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (ops.Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, found", count);
                sw.Reset();

                #endregion           

                #region array.Contains

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    if (CreateArray().Contains(a))
                    {
                        count++;
                    }
                }
                sw.Stop();
                report("array.Contains, inline array, found", count);
                sw.Reset();

                #endregion

                #region switch-statement

                a = GetString().Substring(0, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, not found", count);
                sw.Reset();

                a = GetString().Substring(1, 1); // avoid interned string
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, not interned, found", count);
                sw.Reset();

                #endregion                      

                #region switch-statement

                a = "a";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, not found", count);
                sw.Reset();

                a = "b";
                sw.Start();

                count = 0;
                for (Int32 index = 0; index < ITERATIONS; index++)
                {
                    switch (a)
                    {
                        case "b":
                        case "c":
                            count++;
                            break;
                    }
                }
                sw.Stop();
                report("switch-statement, interned, found", count);
                sw.Reset();

                #endregion
            }
        }

        private static String GetString()
        {
            return "ab";
        }

        private static String[] CreateArray()
        {
            return new String[] { "b", "c" };
        }
    }
}
3 голосов
/ 05 мая 2009

Вы можете использовать регулярные выражения:

if(Regex.IsMatch(a, "b|c"))

Если содержимое «а» может быть длиннее одного символа, используйте это:

if(Regex.IsMatch(a, "^(b|c)$"))
3 голосов
/ 05 мая 2009

Насколько мне известно, это не вариант.

2 голосов
/ 05 мая 2009

Вы можете в определенных ситуациях. А именно, помеченные перечисления:

[Flags]
enum MyEnum {
    None = 0,
    A = 1,
    B = 2,
    C = 4,
    D = 8
}

//...

MyEnum a = MyEnum.B

if((a & (MyEnum.B | MyEnum.C)) > 0)
    // do something

эквивалентно:

if((a & MyEnum.B) > 0 || (a & MyEnum.C) > 0)
    // do something

Причина этого связана с битовыми масками. В двоичном коде

None = 00000
A    = 00001
B    = 00010
C    = 00100
D    = 01000

Итак, когда мы используем | оператор, мы делаем побитовое сравнение, ища любые 1 в столбце и копируем их в результат. Если в столбце нет 1, вы копируете 0.

  B 00010
& C 00100
---------
    00110

Затем, когда мы применяем оператор &, мы ищем 1 во всех строках каждого столбца, прежде чем копировать 1.

  (B & C) 00110
& (a = B) 00010
---------------
          00010

Что> 0, возвращая, таким образом, истину.

Как ни странно, это наиболее эффективный способ сделать это, поскольку он экономит вам числовое сравнение (>) и логический оператор (||), который выполняет все эти замысловатые замыкания и все такое.

2 голосов
/ 05 мая 2009

Нет, не с этим синтаксисом. Но есть много вариантов, чтобы закодировать это.

if ("bc".Contains(a)) { } // Maybe check a.Length == 1, too.

if ((a[0] & 0x62) == 0x62) { } // Maybe check a.Length == 1, too.

if (new String[] { "b", "c" }.Contains(a)) { }

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

0 голосов
/ 05 мая 2009

Нет, это не то, как оператор или (||) работает в C #.

Альтернативное решение, хотя и делает код менее читабельным, - создать функцию, которая проверяет требуемое значение, что-то похожее на:

public static bool Any(object a, params object[] b)
{
    foreach(object item in b)
    {
        if(a == b)
        {
            return true;
        }
    }
    return false;
}
...