foreach中内联运算和运算前计算的区别

Difference between inline operation and calculate before operation in foreach

我简单点(因为我在 Google 上没有找到任何东西,也许是因为我也不知道搜索什么)。

这有什么区别:

foreach(var x in g.GetList())
{
 code
}

还有这个:

IEnumerable<object> list = g.GetList();
foreach(var x in list)
{
 code
}

在性能方面还是在最佳实践方面,或者其他方面?

在下面的代码中,您直接调用了 foreach

中的 g.GetList() 方法
foreach(var x in g.GetList())
{
 code
}

在下面的代码中,您在变量中分配了 g.GetList() 方法,然后您在 foreach 中调用该变量。与第一个代码相比,性能副,没有区别。只是编译器多编译了一行。就这些了。

IEnumerable<object> list = g.GetList();
foreach(var x in list)
{
 code
}

但是如果 g.GetList(); 方法 return 为空,您的第一个代码可能会引发空引用错误。所以最好的做法是在 foreach

中使用 variable/method 之前检查 null 条件
IEnumerable<object> list = g.GetList();
if(list == null)
{
retur false;
}
foreach(var x in list)
{
 code
}

并且由于 type safe,必须使用真实对象而不是使用对象和动态数据类型。

IEnumerable<Employee> list = g.GetList();// as per employee is your class name

Performance is very important for clients, But Standard and understandable coding's are important for developers. I hope you can understand what is am explained.

这两段代码:

foreach(var x in g.GetList())
{
 code
}

IEnumerable<object> list = g.GetList();
foreach(var x in list)
{
 code
}

只有1个不同,那就是你自己把调用g.GetList()的结果放到了一个变量中。

IL-wise,编译器输出的内容,当你编译为 RELEASE 模式时,将 100% 相同.

这是一个示例 LINQPad 程序:

void Main() {  }

static void Method1()
{
    foreach (var x in g.GetList()) { }
}

static void Method2()
{
    IEnumerable<object> list = g.GetList();
    foreach (var x in list) { }
}

static class g
{
    public static IEnumerable<object> GetList() => new List<object>();
}

将为 Method1 和 Method2 生成此 IL 代码:

IL_0000:  call        UserQuery+g.GetList
IL_0005:  callvirt    System.Collections.Generic.IEnumerable<System.Object>.GetEnumerator
IL_000A:  stloc.0     
IL_000B:  br.s        IL_0014
IL_000D:  ldloc.0     
IL_000E:  callvirt    System.Collections.Generic.IEnumerator<System.Object>.get_Current
IL_0013:  pop         
IL_0014:  ldloc.0     
IL_0015:  callvirt    System.Collections.IEnumerator.MoveNext
IL_001A:  brtrue.s    IL_000D
IL_001C:  leave.s     IL_0028
IL_001E:  ldloc.0     
IL_001F:  brfalse.s   IL_0027
IL_0021:  ldloc.0     
IL_0022:  callvirt    System.IDisposable.Dispose
IL_0027:  endfinally  
IL_0028:  ret

所以除了你编写代码的方式之外没有区别。