Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 迭代Linq表达式结果与首先将其分配给变量相同吗?_C#_.net_Linq_Foreach - Fatal编程技术网

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,每个都将从数据库中获取项目。属性文档的第页中也提到了此行为

这通常违反了选择属性和方法的原则:

在下列情况下,请使用方法而不是属性

  • 每次调用该操作时,即使参数不变,也会返回不同的结果
请注意,如果我们再次对该SharePoint示例使用
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>())
{ … }