2009-05-05 69 views
4

我能達到的OR運算符在C#

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

代替

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

+0

您確定要使用|運算符(二進制或)而不是|| (邏輯或)? – 2009-05-05 17:42:17

+0

...你不是說||運營商? – 2009-05-05 17:42:36

+0

正確!我編輯了這篇文章。 – 2009-05-05 17:47:33

回答

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-statement(無論是否首先實際使用字符串)都會給出與簡單或聲明大致相同的結果,這是預期的結果,而數組查找很多更昂貴,這對我來說也是預料之中的。

請修改代碼,並糾正(或評論)它,如果有問題。

而這裏的源代碼,而長:

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" }; 
     } 
    } 
} 
+0

如果數組是靜態分配的,那麼性能測試可能會很有趣(如果表達式花費的時間足夠長以便根據時間開銷進行測量)。 – Richard 2009-05-05 19:46:24

3

據我所知,這是不是一種選擇。

16

那麼,最接近你可以得到的是:

switch (a) { 
    case "b": 
    case "c": 
     // variable a is either "b" or "c" 
     break; 
} 
+0

接受的答案是少代碼,但使用switch語句的開銷較少,我相信。 – 2009-05-05 17:49:50

+0

我推薦此解決方案。首先,它更具可讀性。其次,它的開銷較小。第三,如果邏輯必須在未來發生變化,則維護起來更容易。 – 2009-05-05 17:53:18

+0

接受的答案可能適合單行,但這個不會爲數組分配額外的內存。 – Kon 2009-05-05 18:35:20

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

也許你可以做一些運算符重載,讓你的語法的工作,但是這真的取決於你想要達到什麼目的,難以從簡單的例子來告訴。

0

不,這不是如何運算符(||)如何在C#中工作。

另一種解決方案,但它使代碼的可讀性,是創建檢查你想要的值的函數,類似於:

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

您可以使用正則表達式:

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

如果「A」可能比一個字符使用這種較長的內容:

if(Regex.IsMatch(a, "^(b|c)$")) 
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

(B & C) 00110 
& (a = B) 00010 
--------------- 
      00010 
前1個在每列中的所有行

這是> 0,因此返回true。

奇怪的是,這是最有效的方法,因爲它爲您節省了一個數值比較(>)和一個邏輯運算符(||),它可以完成所有那些奇怪的短路和什麼。