【问题标题】:Whats The Most Efficient Way To Instantiate Worker Variables实例化工作变量的最有效方法是什么
【发布时间】:2010-09-27 13:06:50
【问题描述】:

我应该在 for 循环内部还是外部实例化我的工作变量

例如

一)

bool b = default(bool);

for (int i = 0; i < MyCollection.Length; i++)
{
  b = false;

  foreach(object myObject in myObjectCollection)
  {
    if (object.Property == MyCollection[i].Property)
    {
      b = true;
      break;
    }
  }      

  if (b)
  {
    DoSomethingWith(MyCollection[i]);
  }
}

b)

for (int i = 0; i < MyCollection.Length; i++)
{
  bool b = default(bool);

  foreach(object myObject in myObjectCollection)
  {
    if (object.Property == MyCollection[i].Property)
    {
      b = true;
      break;
    }
  }      

  if (b)
  {
    DoSomethingWith(MyCollection[i]);
  }
}

编辑:似乎普遍认为在 IL 方面没有区别。但是为了可读性和范围的清晰......内部更好

【问题讨论】:

  • 我以前在外面做,但 ReSharper 告诉我在里面做。我会对人们的反应感兴趣
  • "bool b = default(bool)" 很古怪!

标签: c# variables for-loop


【解决方案1】:

由于我误读了代码,已删除先前的答案。 (顺便说一句,在任何地方使用“default(bool)”有点奇怪。)

但是,除非变量被委托等捕获,否则我希望它们要么编译为实际上相同的 IL(在行为和性能方面)。

和以往一样,首先编写最可读的代码。像这样的微观优化是自找麻烦。我同意其他人的建议,即尽可能地限制变量的范围——所以如果你在循环之后需要它,无论如何你别无选择;否则在里面声明。

好的,这是一个测试程序:

using System;

class Test
{
    static void Main() {}

    static void DeclareInside()
    {
        for (int i=0; i < 10; i++)
        {
            bool x = false;
            for (int j=5; j < 20; j++)
            {
                if (i == j)
                {
                    x = true;
                    break;
                }
                if (x)
                {
                    Console.WriteLine("Yes");
                }
            }
        }
    }

    static void DeclareOutside()
    {
        bool x;
        for (int i=0; i < 10; i++)
        {
            x = false;
            for (int j=5; j < 20; j++)
            {
                if (i == j)
                {
                    x = true;
                    break;
                }
                if (x)
                {
                    Console.WriteLine("Yes");
                }
            }
        }
    }
}

生成的 IL(只是 csc Test.cs):

.method private hidebysig static void  DeclareOutside() cil managed
{
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init (bool V_0,
           int32 V_1,
           int32 V_2,
           bool V_3)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.1
  IL_0003:  br.s       IL_0045
  IL_0005:  nop
  IL_0006:  ldc.i4.0
  IL_0007:  stloc.0
  IL_0008:  ldc.i4.5
  IL_0009:  stloc.2
  IL_000a:  br.s       IL_0037
  IL_000c:  nop
  IL_000d:  ldloc.1
  IL_000e:  ldloc.2
  IL_000f:  ceq
  IL_0011:  ldc.i4.0
  IL_0012:  ceq
  IL_0014:  stloc.3
  IL_0015:  ldloc.3
  IL_0016:  brtrue.s   IL_001d
  IL_0018:  nop
  IL_0019:  ldc.i4.1
  IL_001a:  stloc.0
  IL_001b:  br.s       IL_0040
  IL_001d:  ldloc.0
  IL_001e:  ldc.i4.0
  IL_001f:  ceq
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  brtrue.s   IL_0032
  IL_0025:  nop
  IL_0026:  ldstr      "Yes"
  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  nop
  IL_0033:  ldloc.2
  IL_0034:  ldc.i4.1
  IL_0035:  add
  IL_0036:  stloc.2
  IL_0037:  ldloc.2
  IL_0038:  ldc.i4.s   20
  IL_003a:  clt
  IL_003c:  stloc.3
  IL_003d:  ldloc.3
  IL_003e:  brtrue.s   IL_000c
  IL_0040:  nop
  IL_0041:  ldloc.1
  IL_0042:  ldc.i4.1
  IL_0043:  add
  IL_0044:  stloc.1
  IL_0045:  ldloc.1
  IL_0046:  ldc.i4.s   10
  IL_0048:  clt
  IL_004a:  stloc.3
  IL_004b:  ldloc.3
  IL_004c:  brtrue.s   IL_0005
  IL_004e:  ret
} // end of method Test::DeclareOutside

.method private hidebysig static void  DeclareInside() cil managed
{
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init (int32 V_0,
           bool V_1,
           int32 V_2,
           bool V_3)
  IL_0000:  nop
  IL_0001:  ldc.i4.0
  IL_0002:  stloc.0
  IL_0003:  br.s       IL_0045
  IL_0005:  nop
  IL_0006:  ldc.i4.0
  IL_0007:  stloc.1
  IL_0008:  ldc.i4.5
  IL_0009:  stloc.2
  IL_000a:  br.s       IL_0037
  IL_000c:  nop
  IL_000d:  ldloc.0
  IL_000e:  ldloc.2
  IL_000f:  ceq
  IL_0011:  ldc.i4.0
  IL_0012:  ceq
  IL_0014:  stloc.3
  IL_0015:  ldloc.3
  IL_0016:  brtrue.s   IL_001d
  IL_0018:  nop
  IL_0019:  ldc.i4.1
  IL_001a:  stloc.1
  IL_001b:  br.s       IL_0040
  IL_001d:  ldloc.1
  IL_001e:  ldc.i4.0
  IL_001f:  ceq
  IL_0021:  stloc.3
  IL_0022:  ldloc.3
  IL_0023:  brtrue.s   IL_0032
  IL_0025:  nop
  IL_0026:  ldstr      "Yes"
  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0030:  nop
  IL_0031:  nop
  IL_0032:  nop
  IL_0033:  ldloc.2
  IL_0034:  ldc.i4.1
  IL_0035:  add
  IL_0036:  stloc.2
  IL_0037:  ldloc.2
  IL_0038:  ldc.i4.s   20
  IL_003a:  clt
  IL_003c:  stloc.3
  IL_003d:  ldloc.3
  IL_003e:  brtrue.s   IL_000c
  IL_0040:  nop
  IL_0041:  ldloc.0
  IL_0042:  ldc.i4.1
  IL_0043:  add
  IL_0044:  stloc.0
  IL_0045:  ldloc.0
  IL_0046:  ldc.i4.s   10
  IL_0048:  clt
  IL_004a:  stloc.3
  IL_004b:  ldloc.3
  IL_004c:  brtrue.s   IL_0005
  IL_004e:  ret
} // end of method Test::DeclareInside

唯一的区别是变量在堆栈中的位置。

【讨论】:

  • 使用 = default(bool) 只是因为我知道它与说 = false 相同(尽管现在我怀疑自己!)
  • 是的,这与说“= false”是一样的——但乍一看,这是我看到的两个代码示例之间的最大区别。就在循环内部,您对一个使用“= false”,对另一个使用“= default(bool)”。
【解决方案2】:

我同意 siz,我取决于范围,如果变量不能在循环内以外的任何地方使用,则在循环内声明它。如果要在循环结束后使用,则需要在外部声明。

【讨论】:

    【解决方案3】:

    里面。变量的范围应限于它们的实际用途。在外部声明它会将变量范围限定为包含块,这是不必要的,并且可能会导致混淆。

    编辑:我猜这段代码只是为了说明示例,但实际上我会省略无关变量并将其写为:

    for (int i = 0; i < MyCollection.Length; i++)
    {
       foreach(MyObjectClass myObject in myObjectCollection)
       {
            if (myObject.Property == MyCollection[i].Property)
            {
                 DoSomethingWith(MyCollection[i]);
                 break;
            }
       }
    }
    

    【讨论】:

      【解决方案4】:

      与读者一起编写代码是您首先想到的。应该优化一小部分代码。

      通常需要在优化和可读性之间进行权衡。由于大部分人力都花在修改和编辑现有代码上,因此倾向于可读性而不是优化通常是正确的决定。

      这里经常应用 80/20 规则。

      【讨论】:

        【解决方案5】:

        另一点是范围。如果在循环之外声明了一个变量,我是否应该期望它在循环之后使用?这是我通常的假设。

        【讨论】:

          【解决方案6】:

          声明你的变量尽可能接近你使用它们的第一个位置,让编译器担心生成最有效的 IL(至少在这种情况下)。

          【讨论】:

            【解决方案7】:

            内部看起来更干净,但同意 Jon 的观点,IL 将是相同的。

            【讨论】:

              【解决方案8】:

              我喜欢在循环内声明它们,它节省了一行代码(在同一行上声明和设置它),并且更容易看到我在循环范围内外使用了哪些变量,当您处理复杂的事情时,这很好。

              【讨论】:

                猜你喜欢
                • 2019-04-23
                • 1970-01-01
                • 1970-01-01
                • 2012-09-22
                • 1970-01-01
                • 2014-11-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多