4

我能达到

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

代替

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

?

4

7 回答 7

15

好吧,你能得到的最接近的是:

switch (a) {
   case "b":
   case "c":
      // variable a is either "b" or "c"
      break;
}
于 2009-05-05T17:47:00.047 回答
14

不,你可以这样做:

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

所有代码都执行了两次,并且只通过了 nr。报告了 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" };
        }
    }
}
于 2009-05-05T17:40:56.207 回答
3

据我所知,这不是一个选择。

于 2009-05-05T17:41:28.640 回答
3

您可以使用正则表达式:

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

如果“a”的内容可以长于一个字符,请使用:

if(Regex.IsMatch(a, "^(b|c)$"))
于 2009-05-05T17:55:15.970 回答
2

不,不是那种语法。但是有很多选择可以编码。

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)) { }

也许您可以进行一些运算符重载并让您的语法正常工作,但这实际上取决于您想要实现的目标,并且很难从您的简单示例中看出。

于 2009-05-05T17:51:08.850 回答
2

你可以在某些情况下。即,标记的枚举:

[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,因此返回 true。

奇怪的是,这是最有效的方法,因为它为您节省了一个数字比较 (>) 和一个逻辑运算符 (||),它可以完成所有花哨的短路和诸如此类的事情。

于 2009-05-05T18:19:14.803 回答
0

不,这不是 or 运算符 (||) 在 C# 中的工作方式。

另一种解决方案,虽然它降低了代码的可读性,但它是创建一个函数来检查你想要的值,类似于:

public static bool Any(object a, params object[] b)
{
    foreach(object item in b)
    {
        if(a == b)
        {
            return true;
        }
    }
    return false;
}
于 2009-05-05T17:54:49.060 回答