C#最好返回List还是修改现有的?

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)

在这种情况下哪个更好?

Ree*_*sey 6

通常,我通常会尝试避免更改/改变现有集合.因此,我几乎总是喜欢你的第二个选择.

话虽如此,它确实有创建 的缺点List<T>,这意味着更多的内存分配.如果(并且仅当)性能在该特定代码段中是一个问题,您可能需要考虑直接修改输入列表,但我建议选择一个方法名称,这使得显而易见的是您正在改变该集合.


Ser*_*rvy 5

所以你遇到的问题是你有一个递归方法,其中每次调用方法都会在概念上将一些项添加到结果集合中.这导致了两种概念方法,您可以正确识别它们:

  1. 让每个递归调用返回它所代表的所有结果的集合.这要求每次调用都会提取任何递归调用的结果,并将它们添加到自己的集合中.这是相当低效和浪费的; 你最终一遍又一遍地复制数据.(也就是说,除非你使用的数据结构可以有效地"添加来自同一类型的另一个实例的所有结果".A LinkedList(你自己卷起来,因为.NET版本不支持这个)可以做得很好或者也许是一些不可变的数据结构.)

  2. 传递一个可变的集合类型,并让每个递归调用变异集合.这将表现良好,但会导致代码难以推理的问题.你不能只拿出一个"子树"并孤立地看待它.调用者也很尴尬,因为他们需要创建一个集合,将其留空,存储对它的引用,以便在调用方法后可以访问它等.这只是非常容易混淆和容易出错.

选项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此查询的结果,那么最好将"获取所有子项"的逻辑操作从"将集合过滤到这些类型的控件"中分离出来.)