列表<;T>;.插入与堆叠<;T>;.推动

本文关键字:gt lt 推动 列表 插入 | 更新日期: 2023-09-27 18:01:08

我从一个方法返回一个IList<T>

在调用类中,我想在列表/堆栈的开头插入一个值。

List<T>中插入值比在Stack<T>中推送值慢。但要使用堆栈,我需要将其开箱。

那么问题是,开箱还是在List<T>中使用Insert,哪个更好?哪一个更贵?

class MyClass 
{
}
IList<MyClass> Method1()
{
}
class MainClass
{
   List<MyClass> list = (List<MyClass>)Method1();
   list.insert(0,new MyClass{...}); //insert at the start. 
   Stack<MyClass> stack = (Stack<MyClass>)Method1();
   stack.Push(new MyClass{...}); //insert at the start
}

列表<;T>;.插入与堆叠<;T>;.推动

在这两个版本中都没有开箱(尽管第一个版本不会编译..第二个版本在运行时总是失败(-

然而,在任何一种情况下,如果进行转换,则只有当实际的底层实现是该类时,才会起作用。

如果您的方法返回IList<T>,我强烈建议您坚持使用IList<T>成员。将结果转换为List<T>Stack<T>(即:无论内部实现是什么——它不是Stack<T>,因为它没有实现IList<T>(是非常危险的。

返回IList<T>的主要原因是有目的地允许您稍后更改内部实现。Method1在内部可能稍后从List<T>更改为其他IList<T>,这将导致代码意外中断。

话虽如此,如果你知道内部实现可能是某种类型,你可以检查它——但我不会盲目地强制转换。

List<T>中插入值比在Stack<T>中推送值慢

,因为在列表中插入与推送到堆栈是不同的操作。当您将一个新项目插入列表的中间时,随后出现的整个数组必须偏移一个。这是一个O(n(运算。推到堆栈只会将值添加到内部数组的末尾。这是便宜的-O(1(。类似的操作是List<T>.Add

但我确实认为在什么时候使用哪个方面存在误解。对于相同的操作,List<T>Stack<T>在实现方面或性能方面没有区别。唯一的区别在于每个集合公开的功能。您可以模拟在List<T>中弹出到Stack<T>,方法是(添加到列表末尾,然后从末尾删除:list.RemoveAt(list.Count - 1)。在这里,重要的是你想如何使用它。如果要将List<T>用作Stack<T>,则放弃前者,始终使用后者。这会让你的意图更加清晰。这样一来,你以后就不那么容易出错了。

但要使用堆栈,我需要将其开箱。

这里没有开箱。取消装箱是指从引用类型(objectIList<T>(强制转换为值类型(如structs、enums(。Stack<T>不是值类型,因此没有取消装箱。它只是引用转换,保留身份。它尽可能便宜。

所以问题是,开箱还是在List<T>中使用Insert哪个更好?哪一个更贵

  • 您的第二个代码不起作用。Stack<T>不是IList<T>。所以你只有一个选择了。

  • Insert肯定更贵,但这并不意味着你应该使用Stack<T>Stack<T>不会通过索引、从中间删除等方式为您提供随机访问。但如果您只需要一个Stack<T>,请坚持使用。List<T>的用途太通用,您可以做很多事情。

一句话:您要么返回Stack<T>并使用它(更好的性能(,要么返回IList<T>并使用它。最后,先根据使用情况决定。