cat*_*ian 4 c# parameters performance return list
通常,这样做更好吗?
public void Foo1(List<int> list)
{
list.Add(1);
}
Run Code Online (Sandbox Code Playgroud)
或这个:
public List<int> Foo2()
{
List<int> list = new List<int>();
list.Add(1);
return list;
}
Run Code Online (Sandbox Code Playgroud)
我问的原因是因为我现在是第一种方式(除了方法不同,显然更复杂),这要求我总是使用两行来调用方法(这相当于很多)额外的线条):
List<int> list = new List<int>();
Foo1(list);
Run Code Online (Sandbox Code Playgroud)
而第二种方式我可以使用一行:
List<int> list = Foo2();
Run Code Online (Sandbox Code Playgroud)
那么哪个方式更好,时间和空间考虑在内?
编辑:好的,更具体地说,我有一个方法,将类型T的所有控件从ControlCollection添加到List.
public static void GetControlsRec<T>(Control.ControlCollection controlCollection, List<T> resultCollection) where T : Control
{
foreach (Control control in controlCollection)
{
if (control is T)
resultCollection.Add((T)control);
if (control.HasChildren)
GetControlsRec(control.Controls, resultCollection);
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下哪个更好?
通常,我通常会尝试避免更改/改变现有集合.因此,我几乎总是喜欢你的第二个选择.
话虽如此,它确实有创建新 的缺点List<T>,这意味着更多的内存分配.如果(并且仅当)性能在该特定代码段中是一个问题,您可能需要考虑直接修改输入列表,但我建议选择一个方法名称,这使得显而易见的是您正在改变该集合.
所以你遇到的问题是你有一个递归方法,其中每次调用方法都会在概念上将一些项添加到结果集合中.这导致了两种概念方法,您可以正确识别它们:
让每个递归调用返回它所代表的所有结果的集合.这要求每次调用都会提取任何递归调用的结果,并将它们添加到自己的集合中.这是相当低效和浪费的; 你最终一遍又一遍地复制数据.(也就是说,除非你使用的数据结构可以有效地"添加来自同一类型的另一个实例的所有结果".A LinkedList(你自己卷起来,因为.NET版本不支持这个)可以做得很好或者也许是一些不可变的数据结构.)
传递一个可变的集合类型,并让每个递归调用变异集合.这将表现良好,但会导致代码难以推理的问题.你不能只拿出一个"子树"并孤立地看待它.调用者也很尴尬,因为他们需要创建一个集合,将其留空,存储对它的引用,以便在调用方法后可以访问它等.这只是非常容易混淆和容易出错.
选项1,尽管它使程序员更容易,但实际上非常浪费(如果你没有通过使用其他类型的集合进行某种优化,如上所述).如果您确实使用了section选项,我强烈建议将其从调用者中抽象出来.具体来说,使重载接受一个List私有,并具有该方法的单独公共重载,而没有额外的参数,该参数在它创建的列表中传递给私有重载,然后返回该列表.这让调用者认为您正在使用类似于第一种方法的方法,同时仍然获得第二种方法的性能优势.但它仍然使开发变得复杂.
另一种选择是完全避免递归,这是我个人的偏好.当你以迭代方式而不是递归方式解决问题时,所有问题都会消失:
public static IEnumerable<Control> GetAllChildren(this Control root)
{
var stack = new Stack<Control>();
stack.Push(root);
while (stack.Any())
{
var next = stack.Pop();
foreach (Control child in next.Controls)
stack.Push(child);
yield return next;
}
}
Run Code Online (Sandbox Code Playgroud)
(如果您希望特定类型的所有控件都只调用OfType此查询的结果,那么最好将"获取所有子项"的逻辑操作从"将集合过滤到这些类型的控件"中分离出来.)