到底要声明一个变量内部或外部的循环? [英] Is it better to declare a variable inside or outside a loop?

查看:134
本文介绍了到底要声明一个变量内部或外部的循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

时做的更好:

variable1Type foo; 
variable2Type baa; 

foreach(var val in list) 
{
    foo = new Foo( ... ); 
    foo.x = FormatValue(val); 

    baa = new Baa(); 
    baa.main = foo; 
    baa.Do();
}

或者

foreach(var val in list) 
{
    variable1Type foo = new Foo( ... ); 
    foo.x = FormatValue(val); 

    variable2Type baa = new Baa(); 
    baa.main = foo; 
    baa.Do();
}

现在的问题是:什么是快1例或2例? 区别是微不足道的?它是在实际应用中的一样吗? 这可能是一个优化的微,但我真的想知道哪个好。

The question is: What is faster 1 case or 2 case? Is the difference is insignificant? Is it the same in real applications? This may be a optimization-micro, but I really want know which is better.

推荐答案

性能方面,让我们试试具体的例子:

Performance-wise, let's try concrete examples:

public void Method1()
{
  foreach(int i in Enumerable.Range(0, 10))
  {
    int x = i * i;
    StringBuilder sb = new StringBuilder();
    sb.Append(x);
    Console.WriteLine(sb);
  }
}
public void Method2()
{
  int x;
  StringBuilder sb;
  foreach(int i in Enumerable.Range(0, 10))
  {
    x = i * i;
    sb = new StringBuilder();
    sb.Append(x);
    Console.WriteLine(sb);
  }
}

我特意挑这两个值类型和引用类型的情况下,影响的东西。现在,IL他们:

I deliberately picked both a value-type and a reference-type in case that affects things. Now, the IL for them:

.method public hidebysig instance void Method1() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] int32 x,
        [2] class [mscorlib]System.Text.StringBuilder sb,
        [3] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> enumerator)
    L_0000: ldc.i4.0 
    L_0001: ldc.i4.s 10
    L_0003: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32, int32)
    L_0008: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
    L_000d: stloc.3 
    L_000e: br.s L_002f
    L_0010: ldloc.3 
    L_0011: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
    L_0016: stloc.0 
    L_0017: ldloc.0 
    L_0018: ldloc.0 
    L_0019: mul 
    L_001a: stloc.1 
    L_001b: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
    L_0020: stloc.2 
    L_0021: ldloc.2 
    L_0022: ldloc.1 
    L_0023: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(int32)
    L_0028: pop 
    L_0029: ldloc.2 
    L_002a: call void [mscorlib]System.Console::WriteLine(object)
    L_002f: ldloc.3 
    L_0030: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    L_0035: brtrue.s L_0010
    L_0037: leave.s L_0043
    L_0039: ldloc.3 
    L_003a: brfalse.s L_0042
    L_003c: ldloc.3 
    L_003d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_0042: endfinally 
    L_0043: ret 
    .try L_000e to L_0039 finally handler L_0039 to L_0043
}

.method public hidebysig instance void Method2() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 x,
        [1] class [mscorlib]System.Text.StringBuilder sb,
        [2] int32 i,
        [3] class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> enumerator)
    L_0000: ldc.i4.0 
    L_0001: ldc.i4.s 10
    L_0003: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32, int32)
    L_0008: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
    L_000d: stloc.3 
    L_000e: br.s L_002f
    L_0010: ldloc.3 
    L_0011: callvirt instance !0 [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
    L_0016: stloc.2 
    L_0017: ldloc.2 
    L_0018: ldloc.2 
    L_0019: mul 
    L_001a: stloc.0 
    L_001b: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
    L_0020: stloc.1 
    L_0021: ldloc.1 
    L_0022: ldloc.0 
    L_0023: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(int32)
    L_0028: pop 
    L_0029: ldloc.1 
    L_002a: call void [mscorlib]System.Console::WriteLine(object)
    L_002f: ldloc.3 
    L_0030: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    L_0035: brtrue.s L_0010
    L_0037: leave.s L_0043
    L_0039: ldloc.3 
    L_003a: brfalse.s L_0042
    L_003c: ldloc.3 
    L_003d: callvirt instance void [mscorlib]System.IDisposable::Dispose()
    L_0042: endfinally 
    L_0043: ret 
    .try L_000e to L_0039 finally handler L_0039 to L_0043
}

正如你所看到的,除了在堆栈中的顺序编译器恰巧选择 - 这也可以同样是一个不同的顺序 - 它绝对没有影响。反过来,实在是没有任何人给的抖动做出多大用处的,其他是不是给它。

As you can see, apart from the order on the stack the compiler happened to choose - which could just as well have been a different order - it had absolutely no effect. In turn, there really isn't anything that one is giving the jitter to make much use of that the other isn't giving it.

除此之外,有一点不同排序的

Other than that, there is one sort-of difference.

在我的方法1() X 某人被限定在的foreach ,并且不能有意或无意访问它的外面。

In my Method1(), x and sb are scoped to the foreach, and cannot be accessed either deliberately or accidentally outside of it.

在我的方法2() X 某人不知道在编译时可靠地分配在的foreach (编译器不知道的foreach 将进行至少一次循环),所以使用它是被禁止的。

In my Method2(), x and sb are not known at compile-time to be reliably assigned a value within the foreach (the compiler doesn't know the foreach will perform at least one loop), so use of it is forbidden.

到目前为止,还没有真正的区别。

So far, no real difference.

我的可以的但是配置和使用 X 和/或某人的外的foreach 。作为一项规则,我会说,这是可能的作用域差大部分时间,所以我赞成方法1 ,但我可能有一些合理的理由要引用它们(更现实,如果他们不是可能未分配),在这种情况下,我会去方法2

I can however assign and use x and/or sb outside of the foreach. As a rule I would say that this is probably poor scoping most of the time, so I'd favour Method1, but I might have some sensible reason to want to refer to them (more realistically if they weren't possibly unassigned), in which case I'd go for Method2.

不过,这是一个如何的每个code可以延长或否,code不是写一个差的问题。说真的,有没有什么区别。

Still, that's a matter of how the each code can be extended or not, not a difference of the code as written. Really, there's no difference.

这篇关于到底要声明一个变量内部或外部的循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆