لماذا المجمع إضافة متغير محلي غير ضروري

رمز C# هذا:

private void LoadAssignments(AssignmentType assignmentType, Collection assignments)
    {
        bool flag;
        DataTable lessons = this.GetResults(assignmentType);
        try
        {
            IEnumerator enumerator = lessons.Rows.GetEnumerator();
            try
            {
                while (true)
                {
                    flag = enumerator.MoveNext();
                    if (!flag)
                    {
                        break;
                    }
                    DataRow row = (DataRow)enumerator.Current;
                }
            }
            finally
            {
                IDisposable disposable = enumerator as IDisposable;
                flag = disposable == null;
                if (!flag)
                {
                    disposable.Dispose();
                }
            }
        }
        finally
        {
            flag = lessons == null;
            if (!flag)
            {
                lessons.Dispose();
            }
        }
    }

ينتج هذا CIL (. NET 4)

    .method private hidebysig 
    instance void LoadAssignments (
        valuetype TTReporterCore.AssignmentType assignmentType,
        class [mscorlib]System.Collections.ObjectModel.Collection`1 assignments
    ) cil managed 
{
    .locals init (
        [0] bool flag,
        [1] class [System.Data]System.Data.DataTable lessons,
        [2] class [mscorlib]System.Collections.IEnumerator enumerator,
        [3] class [System.Data]System.Data.DataRow row,
        [4] class [mscorlib]System.IDisposable disposable,
        [5] bool flag1
    )

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldarg.1
    IL_0003: call instance class [System.Data]System.Data.DataTable TTReporterCore.TTReader::GetResults(valuetype TTReporterCore.AssignmentType)
    IL_0008: stloc.1
    .try
    {
        IL_0009: nop
        IL_000a: ldloc.1
        IL_000b: callvirt instance class [System.Data]System.Data.DataRowCollection [System.Data]System.Data.DataTable::get_Rows()
        IL_0010: callvirt instance class [mscorlib]System.Collections.IEnumerator [System.Data]System.Data.InternalDataCollectionBase::GetEnumerator()
        IL_0015: stloc.2
        .try
        {
            IL_0016: nop
            IL_0017: br.s IL_0038
            .loop
            {
                IL_0019: nop
                IL_001a: ldloc.2
                IL_001b: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
                IL_0020: stloc.0
                IL_0021: ldloc.0
                IL_0022: stloc.s flag1
                IL_0024: ldloc.s flag1
                IL_0026: brtrue.s IL_002b

                IL_0028: nop
                IL_0029: br.s IL_003d

                IL_002b: ldloc.2
                IL_002c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
                IL_0031: castclass [System.Data]System.Data.DataRow
                IL_0036: stloc.3
                IL_0037: nop

                IL_0038: ldc.i4.1
                IL_0039: stloc.s flag1
                IL_003b: br.s IL_0019
            }

            IL_003d: nop
            IL_003e: leave.s IL_0062
        }
        finally
        {
            IL_0040: nop
            IL_0041: ldloc.2
            IL_0042: isinst [mscorlib]System.IDisposable
            IL_0047: stloc.s disposable
            IL_0049: ldloc.s disposable
            IL_004b: ldnull
            IL_004c: ceq
            IL_004e: stloc.0
            IL_004f: ldloc.0
            IL_0050: stloc.s flag1
            IL_0052: ldloc.s flag1
            IL_0054: brtrue.s IL_0060

            IL_0056: nop
            IL_0057: ldloc.s disposable
            IL_0059: callvirt instance void [mscorlib]System.IDisposable::Dispose()
            IL_005e: nop
            IL_005f: nop

            IL_0060: nop
            IL_0061: endfinally
        }

        IL_0062: nop
        IL_0063: nop
        IL_0064: leave.s IL_007e
    }
    finally
    {
        IL_0066: nop
        IL_0067: ldloc.1
        IL_0068: ldnull
        IL_0069: ceq
        IL_006b: stloc.0
        IL_006c: ldloc.0
        IL_006d: stloc.s flag1
        IL_006f: ldloc.s flag1
        IL_0071: brtrue.s IL_007c

        IL_0073: nop
        IL_0074: ldloc.1
        IL_0075: callvirt instance void [System]System.ComponentModel.MarshalByValueComponent::Dispose()
        IL_007a: nop
        IL_007b: nop

        IL_007c: nop
        IL_007d: endfinally
    }

    IL_007e: nop
    IL_007f: ret
}

لماذا تضيف MSIL flag1 ، متابعة تنفيذ نفس المنطق لتعيين إشارة ، تعيين flag1 إلى إشارة وأخيراً ، تحقق من! flag1. هذا يبدو وكأنه عدم كفاءة مترجم بالنسبة لي.

استكمال: كنت تستخدم JustDecompile Telerik وفي حين أن النتائج تختلف تماما عن ILDASM ، لا يزال يتم إنشاء منطقية إضافية في وضع التصحيح.

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

0
نفس النتيجة في وضع الإصدار.
وأضاف المؤلف kakridge, مصدر
هانس ومايكل - أنتم على حق. يجب أن أكون مخطئا عندما تفكيك بناء الإصدار. لا يزال ، ليس أن نسخة الإصدار محسّنة ، إنها نسخة التصحيح المضافة إليها. إذن ، هل القيمة المنطقية الثانية المطلوبة لأغراض التصحيح ، أم أن هذا خطأ في المحول البرمجي عند وضع علامة على التصحيح؟ لا أرى حاجة للقيمة المنطقية الثانية.
وأضاف المؤلف kakridge, مصدر
يشبه اسم المتغير الفعلي "CS $ 4 $ 0000" ، وليس "flag1". و تتحسن في بناء الإصدار. لست متأكدا ما المجمع الذي تستخدمه ولكن يبدو borken. استخدم ildasm.exe لرؤية هذا.
وأضاف المؤلف Hans Passant, مصدر
لا يوجد شيء ، لهذا السبب تم تحسينها. ليس هناك أي سبب لتوليد مؤقت في بناء التصحيح سواء ، ولكن هذه هي الطريقة التي يعمل بها المجمعين ، فقد كانت مطلوبة إذا بدت الشفرة بشكل مختلف. هم عظام برئاسة إلا إذا طلبت منهم العمل بجدية أكبر. الذي تفعله مع خيار/التحسين.
وأضاف المؤلف Hans Passant, مصدر
ماذا يحدث إذا قمت بالتجميع في وضع Release بدلاً من وضع Debug؟
وأضاف المؤلف Michael Liu, مصدر

2 إجابة

عندما كتبت برنامجًا مشابهًا ، لم يظهر المتغير الإضافي في وضع التحرير. نفس في عرض التجميع ، أظهر التصحيح أن المتغير الإضافي قيد التعيين ([ebp-44h]) والإصدار لا:

<�القوي> تصحيح: </قوي>

enter image description here

على الإصدار: </قوي>

enter image description here

0
وأضاف
يبدو أنك تخطيت الكلمة الأولى من العنوان.
وأضاف المؤلف Kendall Frey, مصدر

يبدو وكأنه يتم إنشاء محلي مؤقت للاحتفاظ بنتائج المقارنة (بمعنى أنه يمكن التخلص منها == فارغة).

جرب هذا المثال:

class Program
{
   static void Main()
   {
       if (1 == 1) return;
   }
}

..is إنتاج IL التالية على مربع بلدي (Microsoft (R) Visual C# 2010 مترجم الإصدار 4.0.30319.1):

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  .maxstack  1
  .locals init (bool V_0)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  br.s       IL_0005
  IL_0005:  ret
}

يتم إنشاء V_0 المحلي ، على الرغم من عدم استخدامه فعليًا. أظن أنه تحسين واضح حتى بالنسبة لـ 'غير محسّن في التجميع :) .. أو على الأرجح: يتم إنشاء كافة التعليمات البرمجية اللازمة لتمكين التصحيح. لا أعرف كيف يمكن استخدامها في جلسة تصحيح الأخطاء ، ولكن أفضل تخمين.

عند ترجمة محسّن (على سبيل المثال ، تهيئة الإصدار) ، لا أراها محلية إضافية.

0
وأضاف