سؤال

هل أستطيع تحقيق

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

بدلاً من

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

?

هل كانت مفيدة؟

المحلول

لا، يمكنك القيام بما يلي:

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

إذا كان لديك لينك الملحقات المتاحة، ولكن هذا بالكاد تحسنا.


ردًا على التعليق حول الأداء، إليك بعض رموز التوقيت الأساسية.لاحظ أنه يجب النظر إلى الكود بعين ناقدة، ربما فعلت أشياء هنا تحريف التوقيت.

النتائج أولا:

||, 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 ستنفذ الكتلة الخاصة به)، ومرة ​​واحدة حيث لم يكن العنصر كذلك (لن يتم تنفيذ الكتلة).تم الإبلاغ عن توقيت كل منها.لقد اختبرت كلاً من المصفوفة المعدة مسبقًا والمصفوفة التي يتم إنشاؤها في كل مرة، وفي هذا الجزء لست متأكدًا من مقدار ما يستنتجه المترجم ويحسنه، فقد يكون هناك خلل هنا.

على أية حال، يبدو أن استخدام عبارة التبديل، مع أو بدون إدخال السلسلة أولاً، يعطي تقريبًا نفس النتائج مثل العبارة أو العبارة البسيطة، وهو أمر متوقع، في حين أن البحث عن المصفوفة أكثر تكلفة بكثير، وهو ما بالنسبة لي كان من المتوقع أيضا.

يرجى تعديل الكود وتصحيحه (أو التعليق عليه) في حالة وجود مشكلات.

وإليك الكود المصدري، طويل نوعًا ما:

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

نصائح أخرى

وكذلك، فإن الأقرب إلى أنه يمكنك الحصول على هو:

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

لمعرفتي أن ليس خيارا.

ويمكنك استخدام التعبير العادية:

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

إذا محتويات "أ" يمكن أن تكون أطول من حرف واحد استخدام هذا:

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

لا، ليس مع ذلك التركيب. ولكن هناك العديد من الخيارات لرمز ذلك.

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

وربما يمكن أن تفعله بعض الحمولة الزائدة المشغل والحصول على عمل في بناء الجملة، ولكن هذا يعتمد حقا على ما تريد تحقيقه ومن الصعب أن نقول من المثال الخاص بك بسيطة.

ويمكنك في بعض الحالات. وهي ترفع علم التعدادات:

[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.

والغريب، وهذا هو أنجع وسيلة للقيام بذلك، لأنه يوفر لك المقارنة العددية (>) والعامل المنطقي (||)، الذي يفعل كل ذلك الدائرة القصيرة الهوى وغيرها.

لا، هذا ليس كيف أو مشغل (||) يعمل في C #.

وحل بديل، على الرغم من أنه يجعل رمز أقل قابلية للقراءة، هو خلق وظيفة بالتحقق من القيمة التي تريدها، شيئا مشابها:

public static bool Any(object a, params object[] b)
{
    foreach(object item in b)
    {
        if(a == b)
        {
            return true;
        }
    }
    return false;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top