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>
,向其中添加一堆节点,然后将其传递给该构造函数,该构造函数获取列表,并用它创建另一个新列表。
编译器是否足够聪明,能够发现它实际上不需要创建两次列表?
这并不是“足够聪明”的情况——编译器按照它的指示去做;您告诉它创建多个列表:它将创建多个列表。
但是,既然你及时释放了它们,它们应该会被相当干净地收集起来,希望是第 0 代。因此,除非你在一个紧密的循环中这样做,否则我不会对此感到太兴奋。
如果您想避免使用列表,您可能考虑 LINQ
Concat
,它允许您附加序列而无需任何额外的列表/集合/等。
如果你告诉它创建一个新对象,它就会创建一个新对象。我认为没有一种优化可以用强制转换和分配来替换构造函数调用 - 编译器必须对构造函数的作用有太多了解才能以这种方式优化它。
从技术上讲,您可以自己完成 -
_context = (List<HtmlNode>)nodes;
- 这就是您希望编译器执行的操作。或者,更好的是,_context = nodes as List<HtmlNode> ?? new List<HtmlNode>(nodes)
。到目前为止,还有些过早优化的味道。您的代码看起来不错,在看到实际的性能问题之前我不会更改任何内容。
不,编译器不能进行这样的优化。
由于构造函数采用 IEnumerable,因此您可以创建表达式而不是列表:
public SharpQuery Add(params HtmlNode[] elements) {
return new SharpQuery(_context.Concat(elements), this);
}
Concat
方法将创建一个表达式,首先返回_context
的项目,然后返回elements
的项目。当在构造函数中创建列表时,它将使用直接从 _context
和 elements
读取的表达式,因此集合仅创建一次。
(JIT 的)编译器无法对此进行优化。它为您创建两个列表。然而问题是,这是否会给您带来性能问题。有了绩效,你就可以衡量、衡量、再衡量。在 98% 的情况下,我认为这段代码不会出现任何问题。