问题 为什么C#LinkedList.RemoveFirst()没有返回删除的值?


C#的LinkedList的RemoveFirst()和RemoveLast()操作是否有一些惯用的,性能的或设计哲学的原因是不会返回删除的值?

现在,如果我想阅读并删除第一个值,我相信咒语是:

LinkedList<string> list = ...;
...
string removed = list.First.Value;
list.RemoveFirst();

在Java中,它将是:

LinkedList<String> list = ...;
...
String removed = list.removeFirst();

别误会我的意思;我并不是说Java更好。只需将Node作为公共构造公开,C#的LinkedList就有了更多的功能。我想了解设计选择。


7679
2018-05-12 18:25


起源

对我而言,似乎归结为方法命名的精确性。该方法应该完全按照它所说的做。如果很容易删除第一个项目但很难阅读它的价值怎么办? (我们知道这不是这种情况,但它可能是这样的 RemoveFirst 方法在不同的情况下,如假设 Directory.RemoveFirst)。 - Justin
我认为你可以覆盖这些方法并构建自己的方法。 - Burimi
我没有检查,但我非常怀疑你可以覆盖这些方法。在C#中,与Java不同,默认情况下方法不是虚拟的 - 你必须用它来声明它们 virtual 如果要允许覆盖它们,请使用关键字。而且,即使是,当覆盖方法时,也无法更改其返回类型。 - Charlie Kilian
因为它的返回类型是无效的 - Larry
虽然您可以以任何方式声明方法,但如果您使用的话 new 关键词。但是,那 new 关键字不会自动将非虚方法变为虚拟方法;相反,它取代了方法。您要覆盖的类的任何父类都无法正确调用“override”方法的新版本。他们将在父类中调用该方法。 - Charlie Kilian


答案:


我无法给出明确的答案,因为我无法读懂设计师的思想 LinkedList<T>。我是什么 能够 说是这样的。

在Java中, LinkedList<E> class实现了 Queue<E> 接口,它反映了设计师的决定:“你知道吗?链接列表可以很容易地用作队列,所以我们不妨让它实现该接口。”和你互动的方式 队列 是通过弹出物品,然后,你知道, 运用 他们的东西(这意味着它是自然的 Pop-like操作返回弹出的元素)。

在.NET中,没有 IQueue<T> 接口。基本上,设计人员做出了不同的决定:“我们所知道的最有效的队列式行为实现是一个简单的基于数组的循环队列。所以如果开发人员想要一个队列,他们应该使用 Queue<T> 上课,就是这样。“

如果开发人员想要使用 LinkedList<T> 作为一个 队列 (或者 双端队列 就此而言,他/她可能正在为他/她实际需要的数据结构选择错误的实现(从.NET的角度来看)。

因此,本着“适当的功能应该做到一件事”的精神,BCL人们选择了 LinkedList<T>.RemoveFirst 做到这一点:删除第一个元素(类似于如何 List<T>.RemoveAt 只是删除指定索引处的元素并且不返回任何内容)。

我不是说这两个决定是对还是错。我认为Java和.NET中标准链表类的不同接口只是反映了链表的不同视图  以及它应该如何 用过的 在两个框架内。


8
2018-05-12 18:45



非常深思熟虑的答案。谢谢。 - Jeff


程序员可能并不总是希望在删除它时返回第一个节点。如果 RemoveFirst 返回节点并且程序员不需要它,它仍然需要内存分配和处理。可选地存储第一个节点(使用 First 在我看来,具有单独的删除功能似乎更灵活。


2
2018-05-12 18:46



我没有考虑过值类型参数。在Java中,返回的值将是对象引用;介于4到8个字节之间。但是由于C#允许更大的值类型,我可以看到这可能会导致一些不可忽略的惩罚。 - Dilum Ranatunga


您是否考虑过使用Queue或Stack集合而不是LinkedList?然后,您可以按下并弹出并获得您想要的行为。


1
2018-05-12 18:29



是的,这就是我正在使用的。但我仍然对这种API设计选择感到好奇。似乎回归虚空是机会的“浪费”。 - Dilum Ranatunga


原因 RemoveFirst 和 RemoveLast 实际上并没有返回值是内部的 LinkedList<T> 将节点存储为 LinkedListNode<T>。该 LinkedListNode 对象有一个概念 Next 和 Previous 但是如果从父集合中删除对象,这些属性指向哪里?


0
2018-05-12 18:51



仅仅因为值包含在节点中并不意味着API无法返回值。此外,返回节点本身是返回null的替代方法。 - Dilum Ranatunga
@Dilum Ranatunga,我同意它可能并且可能应该返回节点 Value 属性。我认为他们(微软)没有这样做的原因是因为它会与其他方法不一致,例如 Find 和 Add 所有返回节点。 - Chris Haas
但是返回节点也没问题......我想的越多,我就越认为这个决定是由一些设计理念驱动的。 - Dilum Ranatunga
我完全同意这是一种设计理念。但是,如果它返回一个节点,你会期望 Next 和 Previous 为空呢?这是我认为它在设计时崩溃的地方。删除的节点几乎只有一个 Value 财产,其他一切都毫无价值。所以MS决定返回一个毫无价值的物体是没有意义的。但是,他们也不想改变转换节点的方法模式,因此他们不能只返回原始值。所以相反,他们走的路对任何人都没有作用,也没有任何回报。这只是我的猜测。我会回来的 Value。 - Chris Haas