Какой самый эффективный способ создания рабочих переменных - PullRequest
1 голос
/ 18 декабря 2008

Должен ли я создавать свои рабочие переменные внутри или вне цикла for

* 1003 Е.Г. *

а)

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]);
  }
}

б)

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. Но для удобочитаемости и ясности объема ... лучше внутри

Ответы [ 8 ]

1 голос
/ 18 декабря 2008

Внутри. Переменные должны быть ограничены их фактическим использованием. Объявляя его вне области видимости, переменная помещается в содержащий блок, что является ненужным и может привести к путанице.

РЕДАКТИРОВАТЬ : Я предполагаю, что этот код только для иллюстрации примера, но на самом деле я бы пропустил постороннюю переменную и записал бы ее как:

for (int i = 0; i < MyCollection.Length; i++)
{
   foreach(MyObjectClass myObject in myObjectCollection)
   {
        if (myObject.Property == MyCollection[i].Property)
        {
             DoSomethingWith(MyCollection[i]);
             break;
        }
   }
}
1 голос
/ 18 декабря 2008

Предыдущий ответ удален, так как я неправильно прочитал код. (Использование «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

Единственная разница в том, где переменные находятся в стеке.

1 голос
/ 18 декабря 2008

внутри выглядит чище, но согласен с Джоном, ИЛ будет таким же.

0 голосов
/ 18 декабря 2008

Я согласен, siz, я зависит от области видимости. Если переменная не должна использоваться нигде, кроме как внутри цикла, объявите ее внутри цикла. Если он должен использоваться после завершения цикла, его необходимо объявить снаружи.

0 голосов
/ 18 декабря 2008

Напишите свой код с помощью ридера как первое, что у вас на уме. Неожиданно небольшая часть кода должна быть оптимизирована.

Часто существует компромисс между оптимизацией и удобочитаемостью. Поскольку большая часть рабочей силы тратится на пересмотр и редактирование существующего кода, обычно правильное решение склоняться к удобству чтения вместо оптимизации.

Здесь часто применяется правило 80/20.

0 голосов
/ 18 декабря 2008

Еще один момент - это сфера. Если переменная объявлена ​​вне цикла, я должен ожидать, что она будет использоваться после цикла? Это то, что я обычно предполагаю.

0 голосов
/ 18 декабря 2008

Объявите ваши переменные как можно ближе к первому месту их использования и дайте компилятору беспокоиться о генерации наиболее эффективного IL (по крайней мере, в этом случае).

0 голосов
/ 18 декабря 2008

Мне нравится объявлять их внутри цикла, это сохраняет строку кода (чтобы объявить и установить ее в одной строке), и мне легче увидеть, какие переменные я использую вне и внутри области видимости цикла, это хорошо, когда вы работаете над чем-то сложным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...