在C#中递归地从列表中删除元素

3
我有一个递归函数,用于在层次结构树中向下搜索并从列表中删除找到的对象:
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个回答

3

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

不会。列表对象是按“值”传递的(但请参见下一个问题)。在C#中,需要使用refout才能"按引用传递", 但这里没有这样做,也不需要这样做。

并修改原始传递的列表?

是的。这是因为传递了列表对象。而且该列表对象被改变了。传递引用类型(使用class定义的任何内容)从来没有隐式地进行复制/克隆/重复。一个对象就是它本身。

现在回到“按值传递”:所传递的“值”是“引用”的值(内部的,不需要关心这个):在像C#这样的语言中,这种调用策略更为常见,被称为对象共享调用/按对象共享方式传递。同一个对象被共享(就好像它被分配给两个不同的变量一样)。 (值类型——一个struct——不同之处在于它们通常会在堆栈上被复制/复制,但List<T>是一个class。)
“或者我应该按照以下方式做些什么?”
这取决于期望的语义。调用者直接或间接地期望副作用吗?突变的副作用会导致意外情况吗?无论哪种方式都要确保进行文档记录。(我更喜欢保证初始对象不会发生突变的方式。)
希望这能解决一些问题。
编程愉快。

请解释-1。我不介意,但如果没有解释,那就毫无意义。 - user166390
2
我唯一的挑剔是你如何称呼以值传递方式传递的 "List对象",这在最好的情况下是误导性的。对象位于堆上,引用是按值传递的,但继续说list object让我感到奇怪。顺便说一句,我在第二次阅读时将-1去掉了。由于我上面提到的问题,第一次我有点误解了你。 - Ed S.
@Ed S. 我希望修改使其更清晰。我试图强调一个对象是...它自己,无论用什么名称(变量)命名。不过,起始部分还是有点强烈了。 - user166390
1
+1 我发现将对象视为按值传递是思考 ref 最有用的方式。 - Kirk Broadhurst
更准确地说,对象引用是按值传递的。引用类型变量保存对对象的引用,并且该引用是按值或按引用传递的。 - phoog

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();

这种方法不会传递你的标签列表,因此不会修改你的原始列表。
这有帮助吗?

我不能选择你的答案作为正确答案,因为它实际上并没有回答我的原始问题,但是我已经给了你一个赞,因为你的解决方案更好。干杯。 - dnatoli
@link664 - 完全理解。我并不是期望直接回答你的问题,而是给你提供一种干净、功能性的方法来实现你想要的,而不必去处理可变集合。 - Enigmativity

0

简短回答 - 您的代码将按您所需的方式执行。

长篇回答 - 您应该阅读有关 ref 关键字的描述。我建议您尽可能多地阅读这些描述;有许多不同的表达方式("我喜欢把它看作是..."),其中一些适合您,而其他一些则不适合。如果您阅读了许多来自理解它的人的描述,则应该会对其有某种程度的理解。

以下是一些可供您开始阅读的链接:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接