我正在考虑更换代码如下:
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
答案 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;
}
具体答案:
它没有创建任何副本,只是枚举。
是
为了表现意识,源代码是最好的。
答案 2 :(得分: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
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;
}