C# 迭代Linq表达式结果与首先将其分配给变量相同吗?
所以,这更难用文字来解释,所以我将给出代码示例。 假设我已经有了一个要筛选的客户列表 基本上,我想知道:C# 迭代Linq表达式结果与首先将其分配给变量相同吗?,c#,.net,linq,foreach,C#,.net,Linq,Foreach,所以,这更难用文字来解释,所以我将给出代码示例。 假设我已经有了一个要筛选的客户列表 基本上,我想知道: foreach(var client in list.Where(c=>c.Age > 20)) { //Do something } 与此相同: var filteredClients = list.Where(c=>c.Age > 20); foreach(var client in filteredClients) { //Do something
foreach(var client in list.Where(c=>c.Age > 20))
{
//Do something
}
与此相同:
var filteredClients = list.Where(c=>c.Age > 20);
foreach(var client in filteredClients)
{
//Do something
}
我被告知第一种方法在每次迭代中执行.Where()
很抱歉,如果这是重复的,我找不到任何相关问题
提前感谢。它们不太一样: 以下是原始C#代码:
静态void ForWithVariable(IEnumerable客户端)
{
var成人=客户,其中(x=>x.年龄>20岁);
foreach(成人var客户)
{
Console.WriteLine(client.Age.ToString());
}
}
WithoutVariable(IEnumerable客户端)的静态void
{
foreach(客户机中的var客户机,其中(x=>x.Age>20))
{
Console.WriteLine(client.Age.ToString());
}
}
以下是这将产生的反编译中间语言(IL)代码(根据):
私有静态void ForWithVariable(IEnumerable客户端)
{
Func arg_21_1;
if((arg_21_1=Program.c.9_1_0)==null)
{
arg_21_1=(Program.c.9_1_0=新函数(Program.c.9.b_1_0));
}
IEnumerable enumerable=客户端,其中(arg_21_1);
foreach(可枚举的当前人员)
{
Console.WriteLine(current.Age.ToString());
}
}
WithOutVariable(IEnumerable客户端)的私有静态void
{
Func arg_22_1;
if((arg_22_1=Program.c.9_2_0)==null)
{
arg_22_1=(Program.c.9_2_0=新函数(Program.c.9.b_2_0));
}
foreach(当前客户中的人员,其中(arg_22_1))
{
Console.WriteLine(current.Age.ToString());
}
}
如您所见,有一个关键区别:
IEnumerable<Person> enumerable = clients.Where(arg_21_1);
IEnumerable enumerable=clients.Where(arg_21_1);
然而,一个更实际的问题是,这些差异是否会影响性能。我做了一个测试来测量这个
class Program
{
public static void Main()
{
Measure(ForEachWithVariable);
Measure(ForEachWithoutVariable);
Console.ReadKey();
}
static void Measure(Action<List<Person>, List<Person>> action)
{
var clients = new[]
{
new Person { Age = 10 },
new Person { Age = 20 },
new Person { Age = 30 },
}.ToList();
var adultClients = new List<Person>();
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 1E6; i++)
action(clients, adultClients);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds.ToString());
Console.WriteLine($"{adultClients.Count} adult clients found");
}
static void ForEachWithVariable(List<Person> clients, List<Person> adultClients)
{
var adults = clients.Where(x => x.Age > 20);
foreach (var client in adults)
adultClients.Add(client);
}
static void ForEachWithoutVariable(List<Person> clients, List<Person> adultClients)
{
foreach (var client in clients.Where(x => x.Age > 20))
adultClients.Add(client);
}
}
class Person
{
public int Age { get; set; }
}
类程序
{
公共静态void Main()
{
度量(ForEachWithVariable);
测量(无变量);
Console.ReadKey();
}
静态空隙测量(作用)
{
var clients=new[]
{
新人{年龄=10},
新人{年龄=20},
新人{年龄=30},
}.ToList();
var adultClients=新列表();
var sw=新秒表();
sw.Start();
对于(变量i=0;i<1E6;i++)
行动(客户、成年客户);
sw.Stop();
Console.WriteLine(sw.elapsedmillisons.ToString());
WriteLine($“{adultClients.Count}找到成人客户端”);
}
静态void ForEachWithVariable(列出客户端、列出成人客户端)
{
var成人=客户,其中(x=>x.年龄>20岁);
foreach(成人var客户)
成人客户。添加(客户);
}
静态void foreachwithout变量(列出客户端、列出成人客户端)
{
foreach(客户机中的var客户机,其中(x=>x.Age>20))
成人客户。添加(客户);
}
}
班主任
{
公共整数{get;set;}
}
在运行了几次程序之后,我没有发现ForEachWithVariable
和foreachwithwithoutvariable
之间有任何显著差异。它们在时间上总是很接近,而且两个都不总是比另一个快。有趣的是,如果我将1E6
更改为1000
,则ForEachWithVariable
实际上一直较慢,大约为1毫秒
因此,我得出结论,对于LINQ to Objects,没有实际的区别。如果您的特定用例涉及LINQ到实体(或SharePoint),则可以运行相同类型的测试。是的,这两个示例在功能上是相同的。一个只存储
可枚举的结果。其中
在访问变量之前存储在变量中,而另一个只直接访问它
要真正了解为什么这不会有什么不同,您必须了解foreach
循环的基本功能。您的示例中的代码(两个)基本上与此等效(我在这里假设了一个已知类型的Client
):
但这是一件根本不同的事情。因为这不是使用foreach
循环,所以我们没有得到用于遍历列表的枚举器对象。相反,我们重复访问activeList.Items
:一次在循环体中按索引获取项,一次在for
循环的继续条件中获取集合的Count
属性值
不幸的是,Microsoft并非始终遵循自己的指导原则,因此即使Items
是对象的属性,它实际上每次都在创建一个新对象。默认情况下,该对象为空,当您第一次从该对象访问某个项目时,该对象只会延迟加载实际项目。因此,上面的代码最终将创建大量的SPListItemCollection
s,每个都将从数据库中获取项目。属性文档的第页中也提到了此行为
这通常违反了选择属性和方法的原则:
在下列情况下,请使用方法而不是属性
- 每次调用该操作时,即使参数不变,也会返回不同的结果
foreach
循环,那么一切都会很好,因为我们将再次只请求一个SPListItemCollection
,并为其创建一个枚举器:
foreach (SPListItem listItem in activeList.Items.Cast<SPListItem>())
{ … }
foreach(activeList.Items.Cast()中的SPListItem listItem)
{ … }
我听说第一种方法在每次迭代中都执行.Where()。
你的朋友不知道他们在说什么
class Program
{
public static void Main()
{
Measure(ForEachWithVariable);
Measure(ForEachWithoutVariable);
Console.ReadKey();
}
static void Measure(Action<List<Person>, List<Person>> action)
{
var clients = new[]
{
new Person { Age = 10 },
new Person { Age = 20 },
new Person { Age = 30 },
}.ToList();
var adultClients = new List<Person>();
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 1E6; i++)
action(clients, adultClients);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds.ToString());
Console.WriteLine($"{adultClients.Count} adult clients found");
}
static void ForEachWithVariable(List<Person> clients, List<Person> adultClients)
{
var adults = clients.Where(x => x.Age > 20);
foreach (var client in adults)
adultClients.Add(client);
}
static void ForEachWithoutVariable(List<Person> clients, List<Person> adultClients)
{
foreach (var client in clients.Where(x => x.Age > 20))
adultClients.Add(client);
}
}
class Person
{
public int Age { get; set; }
}
IEnumerable<Client> x = list.Where(c=>c.Age > 20);
// foreach loop
IEnumerator<Client> enumerator = x.GetEnumerator();
while (enumerator.MoveNext())
{
Client client = enumerator.Current;
// Do something
}
SPList activeList = SPContext.Current.List;
for (int i=0; i < activeList.Items.Count; i++)
{
SPListItem listItem = activeList.Items[i];
// do stuff
}
foreach (SPListItem listItem in activeList.Items.Cast<SPListItem>())
{ … }