C# 列表。插入vs堆栈。推送

C# 列表。插入vs堆栈。推送,c#,.net,performance,generics,C#,.net,Performance,Generics,我正在从方法返回IList 在调用类中,我想在列表/堆栈的开头插入一个值 在列表中插入值比在堆栈中推送值慢。但要使用堆栈,我需要将其取消装箱 所以问题是哪一个更好,取消装箱还是使用插入列表?哪一个更贵 class MyClass { } IList<MyClass> Method1() { } class MainClass { List<MyClass> list = (List<MyClass>)Method1(); list.inser

我正在从方法返回IList

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

在列表中插入值比在堆栈中推送值慢。但要使用堆栈,我需要将其取消装箱

所以问题是哪一个更好,取消装箱还是使用插入列表?哪一个更贵

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
}

在这两个版本中都没有取消装箱,尽管第一个版本不会编译。。第二个在运行时总是失败-

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

如果您的方法返回一个IList,我强烈建议您坚持使用IList成员。将结果转换为列表或堆栈,即:无论内部实现是什么——这不是堆栈,因为它不实现IList是非常危险的

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


这就是说,如果您知道内部实现可能是某种类型,您可以检查它-但我不会盲目地强制转换。

在这两个版本中,您都没有取消绑定,尽管第一个版本不会编译。。第二个在运行时总是失败-

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

如果您的方法返回一个IList,我强烈建议您坚持使用IList成员。将结果转换为列表或堆栈,即:无论内部实现是什么——这不是堆栈,因为它不实现IList是非常危险的

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

也就是说,如果您知道内部实现可能是某种类型,您可以检查它——但我不会盲目地强制转换

在列表中插入值比在堆栈中推送值慢

是的,因为在列表中插入与推送到堆栈是不同的操作。当您在列表的中间插入一个新项时,随后出现的整个数组必须移位一。这是一个正在进行的手术。推送到堆栈只会将值添加到内部数组的末尾。这是便宜的O1。可比较的操作是列表。添加

但我确实认为,关于何时使用哪一种,这里存在误解。对于同一操作,列表和堆栈在实现方面或性能方面没有区别。唯一的区别在于每个集合公开的特性。您可以通过添加到列表的末尾并从末尾删除来模拟弹出以在列表中堆叠:List.RemoveAtlist.Count-1。在这里,重要的是你想如何使用它。如果要将列表用作堆栈,则放弃前者,始终使用后者。这会让你的意图更清晰。因此,您在将来更不容易出错

但要使用堆栈,我需要将其取消装箱

这里没有拆箱。取消装箱是指从引用类型对象IList强制转换为值类型,如结构、枚举。堆栈不是值类型,因此不存在解装箱。它只是引用转换,保留了身份。它尽可能便宜

所以问题是哪一个更好,取消装箱还是使用插入列表?哪一个更贵

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
}
你的第二个代码不起作用。堆栈不是IList。所以你只有一个选择了

Insert的成本肯定更高,但这并不意味着您应该使用堆栈。堆栈不会通过索引、从中间删除等方式为您提供随机访问。但如果您只需要一个堆栈,请坚持使用它。这个列表太笼统了,你可以用它做很多事情

一句话:要么返回堆栈并更好地使用它,要么返回IList并使用它更多的功能。最后,先根据用途来决定

在列表中插入值比在堆栈中推送值慢

是的,因为在列表中插入与推送到堆栈是不同的操作。当您在列表的中间插入一个新项时,随后出现的整个数组必须移位一。这是一个正在进行的手术。推送到堆栈只会将值添加到内部数组的末尾。这是便宜的O1。可比较的操作是列表。添加

但我确实认为,关于何时使用哪一种,这里存在误解。对于同一操作,列表和堆栈在实现方面或性能方面没有区别。唯一的区别在于每个集合公开的特性。您可以通过添加到列表末尾并从末尾删除来模拟弹出以在列表中堆叠:List.RemoveAtlist.Count- 1.在这里,重要的是你想如何使用它。如果要将列表用作堆栈,则放弃前者,始终使用后者。这会让你的意图更清晰。因此,您在将来更不容易出错

但要使用堆栈,我需要将其取消装箱

这里没有拆箱。取消装箱是指从引用类型对象IList强制转换为值类型,如结构、枚举。堆栈不是值类型,因此不存在解装箱。它只是引用转换,保留了身份。它尽可能便宜

所以问题是哪一个更好,取消装箱还是使用插入列表?哪一个更贵

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
}
你的第二个代码不起作用。堆栈不是IList。所以你只有一个选择了

Insert的成本肯定更高,但这并不意味着您应该使用堆栈。堆栈不会通过索引、从中间删除等方式为您提供随机访问。但如果您只需要一个堆栈,请坚持使用它。这个列表太笼统了,你可以用它做很多事情


一句话:要么返回堆栈并更好地使用它,要么返回IList并使用它更多的功能。最后,先根据用途来决定

's不实现IList接口,所以应该总是失败。Stack不实现IList,所以整个问题都没有意义。IList说我的行为就像一个列表,所以如果您愿意,可以通过索引访问我。斯塔克说我是斯塔克。只能从顶部访问我。有点问题,不是吗?对不起。我没有运行代码,但它编译并编写了问题。我的错。@Mangesh:上面的列表版本不会编译-堆栈版本会编译,但是每次运行时都会失败。@Reed:谢谢Reed,你说的对。我修改了问题“不实现IList接口,所以应该总是失败。Stack没有实现IList,所以整个问题都没有意义。IList说我的行为就像一个列表,所以如果您愿意,可以通过索引访问我。斯塔克说我是斯塔克。只能从顶部访问我。有点问题,不是吗?对不起。我没有运行代码,但它编译并编写了问题。我的错。@Mangesh:上面的列表版本不会编译-堆栈版本会编译,但每次运行时都会失败。@Reed:谢谢Reed,你是对的。我修改了问题。我删除了我的答案,建议对堆栈进行测试强制转换,这是不可能的,因为堆栈没有实现IList。你的强烈建议实际上是一个要求:@SixlettVariables:是的,我知道-我在提到这一点时也做了编辑-我认为这是一个例子,因为原始问题中的两种情况都不会编译;我已经删除了我的答案,它建议对堆栈进行测试转换,这是不可能的,因为堆栈并没有实现IList。你的强烈建议实际上是一个要求:@SixlettVariables:是的,我知道-我在提到这一点时也做了编辑-我认为这是一个例子,因为原始问题中的两种情况都不会编译;