linq如何在引擎盖下工作?

时间:2013-07-13 22:41:22

标签: c# linq

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

        foreach (var meshCut in meshCuts0)
        {
            ComputePolygons(meshCut, polygons);
        }
        foreach (var meshCut in meshCuts1)
        {
            ComputePolygons(meshCut, polygons);
        }

linq看起来像这样:

        meshCuts0.Concat(meshCuts1).ForEach(m => ComputePolygons(m, polygons));

我不知道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;
        }
    }

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);
}

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

修改2

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

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

3 个答案:

答案 0 :(得分:10)

首先,只有当 ForEach上引入IEnumerable<T>扩展方法时,您的代码才有效。我建议你不这样做 - 请参阅Eric Lippert's blog post我同意的原因。

我建议你把它写成:

foreach (var meshCut in meshCuts0.Concat(meshCuts1))
{
    ComputePolygons(meshCut, polygons);
}

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

我希望Mono的行为方式相同 - Concat 非常简单。事实上,由于Mono是开源的,你可以check it for yourself。 (它可能随着时间的推移而移动,当然......)

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

答案 1 :(得分:4)

这就是linq concat在幕后工作的方式。

Microsoft .net framework 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; 
}

单声道(来源: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;
}

具体答案:

  1. 它没有创建任何副本,只是枚举。

  2. 为了表现意识,源代码是最好的。

答案 2 :(得分:1)

  1. 它就像你描述的一样。您可以下载名为JetBrains dotPeek - .net反编译器的免费工具。您可以将每个程序集,甚至标准程序集加载到反编译器并获取源代码。如果您查看程序集System.Core,命名空间System.Linq,类Enumerable,您可以看到:

    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; 
    }
    

    谈论LINQ - 它是懒惰的,每个linq扩展方法都使用延迟计算。有一个好人Jon Skeet,他有一个博客。有很多文章命名为“Reimplementing LINQ to Objects:Part”,所有文章都可以通过标签'linq'找到:link

  2. Mono是开源项目。您可以在github找到来源。可以在此处创建类Enumerable:link。和Concat的源代码:

    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;
    }