以下两个陈述有什么区别?

时间:2013-07-17 13:35:46

标签: c# performance linq count where

我们可以通过以下声明来计算过程

var query = Process.GetProcesses()
             .Where(m => m.ProcessName.StartsWith("S")).Count();

但是ReShaper建议我跟随声明

var query = Process.GetProcesses().Count(m => m.ProcessName.StartsWith("S"));

我的问题是......如果考虑性能问题,哪一个更好?

2 个答案:

答案 0 :(得分:4)

第一个语句将在内部创建WhereIterator,它将迭代源并应用谓词。计算计算如下:

var iterator = new WhereArrayIterator<TSource>((TSource[]) source, predicate);

int num = 0;

using (IEnumerator<TSource> enumerator = iterator.GetEnumerator())
{
   while (enumerator.MoveNext())
       num++;      
}

return num;

但是第二个语句不会创建迭代器 - 它将直接在源序列上迭代时应用谓词:

int num = 0;

foreach (TSource local in source)
{
    if (predicate(local))        
        num++;        
}

return num;

所以,第二个语句稍微表现更好。

答案 1 :(得分:1)

两个查询的IL结果是:

Process.GetProcesses().Count(m => m.ProcessName.StartsWith("S"));

IL_0001:  call        System.Diagnostics.Process.GetProcesses
IL_0006:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_000B:  brtrue.s    IL_0020
IL_000D:  ldnull      
IL_000E:  ldftn       b__0
IL_0014:  newobj      System.Func<System.Diagnostics.Process,System.Boolean>..ctor
IL_0019:  stsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_001E:  br.s        IL_0020
IL_0020:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0025:  call        System.Linq.Enumerable.Count

Process.GetProcesses().Where(m => m.ProcessName.StartsWith("S")).Count();

IL_0001:  call        System.Diagnostics.Process.GetProcesses
IL_0006:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_000B:  brtrue.s    IL_0020
IL_000D:  ldnull      
IL_000E:  ldftn       b__0
IL_0014:  newobj      System.Func<System.Diagnostics.Process,System.Boolean>..ctor
IL_0019:  stsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_001E:  br.s        IL_0020
IL_0020:  ldsfld      UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0025:  call        System.Linq.Enumerable.Where
IL_002A:  call        System.Linq.Enumerable.Count

b__0:
IL_0000:  ldarg.0     
IL_0001:  callvirt    System.Diagnostics.Process.get_ProcessName
IL_0006:  ldstr       "S"
IL_000B:  callvirt    System.String.StartsWith
IL_0010:  stloc.0     // CS$1$0000
IL_0011:  br.s        IL_0013
IL_0013:  ldloc.0     // CS$1$0000
IL_0014:  ret 

原因很明显,不是吗?

执行时间的差异不是很大,但第一个方法调用较少,所以看起来更好。