在C#中以递归方式从列表中删除

时间:2011-09-12 00:01:16

标签: c# .net recursion

我有以下递归函数,用于搜索分层树并从列表中删除找到的对象:

private List<Tag> RemoveInvalidTags(Device device, List<Tag> tags)
{
   var childDevices = device.ChildDevices.Select(c => c.ChildDevice);

   foreach (var child in childDevices)
   {
      tags.Remove(child.Tag);
      RemoveInvalidTags(child, tags);
   }

   return tags;
}

我期望这样做是从标签列表中删除此级别的所有子设备标签,为您的孩子递归调用该函数,然后将该列表返回到上一级别。

这会通过引用传递标签列表并修改原始传递的列表吗?或者我应该按照

的方式做些什么
validTags = CollectValidTags(child, tags);

并将所有返回的列表相加?

3 个答案:

答案 0 :(得分:3)

  
    

这会通过引用传递标签列表

  

没有。 列表对象按“值”传递(但请参阅下一步)。 C#中"pass by reference"需要refout,但这里没有完成,也不需要。{/ p>

  
    

并修改原始传递的列表?

  

是。这是因为传递了列表对象列表对象发生了变异。传递引用类型(使用class定义的任何内容)从不隐式地复制/克隆/复制。一个对象就是它。

现在,回到“按值传递”:“传递的值”是“引用”的值(内部,无需关注此内容):此调用策略更好地称为Call/Pass By Object Sharing in像C#这样的语言。 同一对象共享(就像它被分配给两个不同的变量一样)。 (值类型 - struct - 不同之处在于它们(经常)在堆栈上被复制/复制,但List<T>class 。)

  
    

或者我应该按照

的方式做些什么   

这取决于所需的语义。调用者是否期望直接或间接地产生副作用?突变副作用会导致意外情况吗?确保以任何一种方式记录。 (我更喜欢保证初始对象不会发生变异的方式。)

希望清除一些事情。

快乐的编码。

答案 1 :(得分:2)

在您的代码中,您正在修改tags参数中的项目,并将修改后的列表作为结果传回。您希望避免以这种方式修改列表 - 特别是在可能导致您在许多情况下悲伤的循环内部。

我有一个基于LINQ的替代方案。

如果我理解你的代码的意图,你想做这样的事情:

Func<Device, IEnumerable<Device>> flatten = null;
flatten = d =>
{
    return (new [] { d }).Concat(
        from c in d.ChildDevices
        from f in flatten(c)
        select f);
};

var collectedValidTags = flatten(device).Select(d => d.Tag);

var result = tags.Except(collectedValidTags).ToList();

此方法不会传递您的标记列表,因此无法修改原始列表。

这有帮助吗?

答案 2 :(得分:0)

简短回答 - 您的代码将按您的要求执行。

答案很长 - 您应该阅读ref关键字的内容说明。我建议你阅读尽可能多的描述;有许多不同的方式来表达它(“我喜欢把它想象成......”),有些会为你效劳,而有些则不会。如果您阅读了许多描述(来自理解它的人),那么某种理解应该适合您。

这是一个让你入门的清单: