有时我必须运行一个循环,其中列表或数组来自函数。
我通常这样做:
Dim list = SomeClass.GetMyList()
For Each item in list
'Do some stuff
Next
是否与:
相同For Each item in SomeClass.GetMyList()
'Do some stuff
Next
我通常采用第一种方式,因为我认为第二种方式是每次开始下一次迭代时都会进行调用,因此会浪费一些时间。
我是这样认为的吗?或者我可以继续第二种方式,因为编译器足够聪明,不会每轮都进行一次调用吗?
答案 0 :(得分:3)
只有for
块内的 重复,而不是其初始化。
您的第二个选项与第一个选项相同,只是使用一个未命名的临时变量,其结果为GetMyList()
。如果有的话,由于这个原因,它可能更多有效......尽管一个好的优化器会使两段代码无论如何相同。
正如评论中所提到的,调试人员会非常清楚这一点,并且无数其他原因是一个非常宝贵的工具。
答案 1 :(得分:2)
方法#1 会在方法的其余部分范围内为您提供对列表的引用。
方法#2 在引用列表的幕后创建一个变量,但在for循环后该变量超出范围
对于范围界定,我更喜欢#2,但我也对简洁的代码保持公正。如果GetMyList
返回引用类型(例如List<T>
或数组),则可能会出现一些意外的副作用。
Public Sub Foo()
Dim someClass As New SomeClass()
' this variable stays in scope after the following For Each loop
Dim list = someClass.GetMyList()
For Each item In list
Console.Write(item)
Next
Console.WriteLine()
' now we can sort the backing field - did you intend for this to happen?
list.Sort()
' the following For Each loop doesn't leave any reference behind
For Each item In someClass.GetMyList()
Console.Write(item)
Next
End Sub
Private Class SomeClass
Private _list As List(Of Integer) = {3, 2, 1}.ToList()
Public Function GetMyList() As List(Of Integer)
Return _list
End Function
End Class
Foo()写道:
321
123
所以你可以在完成它之后实际操作后备区域!
答案 2 :(得分:1)
让我们举一个简单的例子
信息不多,我认为GetMyList
是list(of integer)
Module Module1
Sub Main()
test1()
test2()
Console.ReadKey(False)
End Sub
Sub test1()
Dim list = SomeClass.GetMyList()
For Each item In list
Console.WriteLine(item)
Next
End Sub
Sub test2()
For Each item In SomeClass.GetMyList()
Console.WriteLine(item)
Next
End Sub
End Module
Class SomeClass
Public Shared Function GetMyList() As List(Of Integer)
Dim aList = New List(Of Integer)
aList.Add(1)
aList.Add(2)
aList.Add(3)
Console.WriteLine("I am in the function now")
Return aList
End Function
End Class
您可以自己运行以查看行为
现在让我们看一下实际的IL(用debug编译)
test1代码;
.method public static
void test1 () cil managed
{
// Method begins at RVA 0x2120
// Code size 64 (0x40)
.maxstack 1
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
[1] int32 item,
[2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> VB$t_struct$L0,
[3] bool VB$CG$t_bool$S0
)
IL_0000: nop
IL_0001: call class [mscorlib]System.Collections.Generic.List`1<int32> ConsoleApplication1.SomeClass::GetMyList()
IL_0006: stloc.0
IL_0007: nop
.try
{
IL_0008: ldloc.0
IL_0009: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000e: stloc.2
IL_000f: br.s IL_0021
// loop start (head: IL_0021)
IL_0011: ldloca.s VB$t_struct$L0
IL_0013: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0018: stloc.1
IL_0019: ldloc.1
IL_001a: call void [mscorlib]System.Console::WriteLine(int32)
IL_001f: nop
IL_0020: nop
IL_0021: ldloca.s VB$t_struct$L0
IL_0023: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0028: stloc.3
IL_0029: ldloc.3
IL_002a: brtrue.s IL_0011
// end loop
IL_002c: nop
IL_002d: leave.s IL_003e
} // end .try
finally
{
IL_002f: ldloca.s VB$t_struct$L0
IL_0031: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_0037: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003c: nop
IL_003d: endfinally
} // end handler
IL_003e: nop
IL_003f: ret
} // end of method Module1::test1
test2代码;
.method public static
void test2 () cil managed
{
// Method begins at RVA 0x217c
// Code size 62 (0x3e)
.maxstack 1
.locals init (
[0] int32 item,
[1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32> VB$t_struct$L0,
[2] bool VB$CG$t_bool$S0
)
IL_0000: nop
IL_0001: nop
.try
{
IL_0002: call class [mscorlib]System.Collections.Generic.List`1<int32> ConsoleApplication1.SomeClass::GetMyList()
IL_0007: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000c: stloc.1
IL_000d: br.s IL_001f
// loop start (head: IL_001f)
IL_000f: ldloca.s VB$t_struct$L0
IL_0011: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::get_Current()
IL_0016: stloc.0
IL_0017: ldloc.0
IL_0018: call void [mscorlib]System.Console::WriteLine(int32)
IL_001d: nop
IL_001e: nop
IL_001f: ldloca.s VB$t_struct$L0
IL_0021: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: brtrue.s IL_000f
// end loop
IL_002a: nop
IL_002b: leave.s IL_003c
} // end .try
finally
{
IL_002d: ldloca.s VB$t_struct$L0
IL_002f: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
IL_0035: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003a: nop
IL_003b: endfinally
} // end handler
IL_003c: nop
IL_003d: ret
} // end of method Module1::test2
唯一不同的是在内存中调用/加载GetMyList
引用时
首先在局部变量中加载它,第二个在循环开始时加载它
因此两种情况都会做同样的事情。