编译器会优化两次创建此列表吗?

时间:2010-11-08 07:33:21

标签: c# optimization compiler-construction

public SharpQuery Add(params HtmlNode[] elements)
{
    var nodes = new List<HtmlNode>(_context.Count + elements.Length);
    nodes.AddRange(_context);
    nodes.AddRange(elements);
    return new SharpQuery(nodes, this);
}

public SharpQuery(IEnumerable<HtmlNode> nodes, SharpQuery previous = null)
{
    if (nodes == null) throw new ArgumentNullException("nodes");
    _previous = previous;
    _context = new List<HtmlNode>(nodes);
}

我有一大堆函数可以创建一个新的List<T>,向它添加一堆节点,然后将它传递给那个获取列表的构造函数,并创建另一个新列表它

编译器是否足够智能以确定它不需要两次创建列表?

4 个答案:

答案 0 :(得分:5)

这不是一个“足够聪明”的情况 - 编译器按照它所说的去做;你告诉它创建多个列表:它将创建多个列表。

然而,由于你及时发布它们应该收集得相当干净,希望gen-0。因此,除非你在紧密的循环中这样做,否则我不会对此感到太兴奋。

如果你想避免列表,可能会考虑LINQ Concat,它允许你附加序列而不需要任何额外的列表/集合等。

答案 1 :(得分:2)

不,编译器不能做那样的优化。

当构造函数采用IEnumerable时,您可以创建表达式而不是列表:

public SharpQuery Add(params HtmlNode[] elements) {
  return new SharpQuery(_context.Concat(elements), this);
}

Concat方法将创建一个表达式,该表达式首先返回_context的项目,然后返回elements的项目。在构造函数中创建列表时,它将使用直接从_contextelements读取的表达式,因此集合仅创建一次。

答案 2 :(得分:2)

如果你告诉它创建一个新对象,它将创建一个新对象。我不认为有一个优化可以用转换和分配替换构造函数调用 - 编译器必须知道构造函数能够以这种方式优化它的方式。

从技术上讲,你可以自己做 - _context = (List<HtmlNode>)nodes; - 这就是你希望编译器做的事情。或者,更好,_context = nodes as List<HtmlNode> ?? new List<HtmlNode>(nodes) 但无论哪种情况,列表都可能在您的类之外进行修改,因此您必须确保它不会导致意外行为。

到目前为止,它还有一种过早优化的气味。你的代码看起来很好,在看到实际的性能问题之前我不会改变任何东西。

答案 3 :(得分:1)

编译器(JIT)无法对其进行优化。它会为您创建两个列表。但问题是,这是否会给您带来性能问题。通过性能,您可以进行测量,测量和测量。在98%的情况下,我认为这段代码不会给出任何问题。