linq如何在引擎盖下工作?

daw*_*daw 1 c# linq

我正在考虑替换代码如下:

        foreach (var meshCut in meshCuts0)
        {
            ComputePolygons(meshCut, polygons);
        }
        foreach (var meshCut in meshCuts1)
        {
            ComputePolygons(meshCut, polygons);
        }
Run Code Online (Sandbox Code Playgroud)

linq看起来像这样:

        meshCuts0.Concat(meshCuts1).ForEach(m => ComputePolygons(m, polygons));
Run Code Online (Sandbox Code Playgroud)

我不知道linq是如何实现的,所以我不确定性能后果.我很感激一些帮助.

1)

Concat会创建一个列表副本,还是只是一个枚举器做这样的事情:

    public static IEnumerable<T> Concat<T>(IEnumerable<T> a, IEnumerable<T> b)
    {
        foreach (var t in a)
        {
            yield return t;
        }
        foreach (var t in b)
        {
            yield return t;
        }
    }
Run Code Online (Sandbox Code Playgroud)

2)

这在Mono上是否会出现同样的行为?

3)

是否有任何参考解释如何实现linq api功能以提高性能?

谢谢!

编辑

好的,没有ForEach,所以我假设我也定义了这样的东西:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach(T item in source)
        action(item);
}
Run Code Online (Sandbox Code Playgroud)

真正的问题是Concat是否会成为一个代价高昂的开销只是为了减少代码,感谢评论,我现在明白它不是.

编辑2

啊,Jon Skeet建议不要添加ForEach ......所以我不会!

http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx

Jon*_*eet 10

首先,如果你的代码只会工作引入了ForEach可拓方法IEnumerable<T>.我建议你不要这样做 - 请参阅Eric Lippert的博客文章,原因我同意.

我建议你把它写成:

foreach (var meshCut in meshCuts0.Concat(meshCuts1))
{
    ComputePolygons(meshCut, polygons);
}
Run Code Online (Sandbox Code Playgroud)

Concat执行得很好 - 它只是迭代第一个序列然后是第二个序列,随着时间的推移产生项目.它不会缓冲所有元素.对于你要添加的额外级别的间接性,会有非常轻微的性能损失,但这就是全部.

我期望单声道的行为以同样的方式- Concat非常简单的.事实上,由于Mono是开源的,您可以自己检查.(它可能随着时间推移,当然......)

不久之前,我在博客上详细介绍了LINQ to Objects,从头开始重新实现了整个过程并记录了其性能的各个方面,包括哪些方面有改进的余地.有关详细信息,请参阅我的Edulinq博客系列.

  • @daw:我可能会使用`Concat` ...可能有一个额外的局部变量,例如`var allCuts = meshCuts0.Concat(meshCuts1); foreach(在allCuts中使用var meshCut)...` (2认同)

lig*_*cko 5

这就是 linq concat 在底层的工作原理。

微软.net框架4.0:

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) {
    if (first == null) throw Error.ArgumentNull("first");
    if (second == null) throw Error.ArgumentNull("second");
    return ConcatIterator<TSource>(first, second); 
}

static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second) { 
    foreach (TSource element in first) yield return element;
    foreach (TSource element in second) yield return element; 
}
Run Code Online (Sandbox Code Playgroud)

单声道(来源:https://github.com/mono/mono/blob/master/mcs/class/System.Core/System.Linq/Enumerable.cs#L584

public static IEnumerable<TSource> Concat<TSource> (this IEnumerable<TSource> first, IEnumerable<TSource> second)
{
    Check.FirstAndSecond (first, second);

    return CreateConcatIterator (first, second);
}

static IEnumerable<TSource> CreateConcatIterator<TSource> (IEnumerable<TSource> first, IEnumerable<TSource> second)
{
    foreach (TSource element in first)
        yield return element;
    foreach (TSource element in second)
        yield return element;
}
Run Code Online (Sandbox Code Playgroud)

具体答复:

  1. 它不会创建任何副本,它只是枚举。

  2. 是的。

  3. 对于注重性能的人来说,源代码是最好的。