在C#中从List<item>中删除列表项后的行为

5
我有一个列表List <Bitmap> memory = new List<Bitmap>();。我在用这个列表保存图像状态,以便在处理图像的简单程序中使用。我想要实现撤销和重做操作,它们将在内存中保存的状态之间迭代(即保存在列表memory中)。

内存将仅具有有限的范围,例如20个状态,这意味着当我进行第21次图像修改时,我将删除第一个状态。可能通过操作memory.RemoveAt(0);来实现。那么列表会发生什么变化?我需要一个比之前少1项的列表,并且索引向左移动。

我有一个列表list.Count = 20,我删除第一项,我希望list.Count = 19并且索引向左移动——就像修剪空闲空间一样,所以原始列表的索引1现在将具有索引0,原始索引的索引2将具有索引1等。我找到了一个列表的方法TrimExcess,它可以做到我想要的,但我不确定。

当我有19个项目的列表时,我可以通过Add()将新状态保存到最后一个位置,这样我又有了20个列表。


3
谁阻止你去尝试呢? - V4Vendetta
3
这里可能更适合使用栈(stack),在Stack Overflow上有一些类似的问题可供参考。 - Mike Miller
3
栈绝对不适合。栈是一种LIFO结构,而OP需要的是FIFO结构。 - Sani Huttunen
你应该尽可能地重复使用旧的位图(Bitmap),或者至少清理它们。 - CodesInChaos
1
@AdamHouldsworth:他确实已经表达了他想要的:... "memory.RemoveAt(0); ... 我删除第一个项目...原始列表的索引1现在将具有索引0..." 这显然是一个FIFO结构。 - Sani Huttunen
显示剩余12条评论
4个回答

15
不要混淆List和数组。数组具有固定的位置和大小,而列表则没有。
对于数组,不存在“添加”或“删除”项的情况。数组始终具有创建时分配的长度。
列表的长度是动态的。你可以添加项目来增长列表,删除项目来缩小列表。如果向列表中添加一个项目,则该项目始终附加到列表末尾(你可以调用Insert在指定位置插入)。
但是,在任何给定时间,在列表中的条目将从0开始索引,范围为Count-1(“基于零的”)。即使你在列表“中间”的位置X删除一个项目,该索引处仍然会有一个项目(之前在位置X + 1的项目)。
总结:你在“我需要什么”段落中描述的内容是在你的代码中自动完成的,无需进一步操作。
关于TrimExcess方法:列表具有Count(列表中实际元素的数量)和Capacity(列表可以承载的内部元素数量,无需重新调整其内部结构)。Capacity可能大于Count,因为列表在添加/删除时需要重新组织其项目所存储的数据结构。
为了节省添加时间,Capacity以较大的步骤增长。例如,向已满的列表添加一个项目时,内部会创建4个新的“位置”,以便连续添加不会引起太多开销。 TrimExcess所做的是重新组织列表的内部数据结构,使CapacityCount相匹配。这需要更多时间,当列表中的项越多时,因此只有在确定不需要再添加/删除任何元素时才应调用TrimExcess

在您的情况下:不要使用 TrimExcess 方法。

Capacity 不限制列表的大小!在 C# 中,没有创建最多只能容纳 X 个元素的列表选项。您需要自己实现。


我可以问一个小问题吗?在删除 Bitmap 之前,我应该调用 Dispose 方法吗?有人提到过这个问题。我不确定垃圾回收器在这种情况下(从列表中删除 Bitmap)如何工作,因为我习惯于使用 Java 并了解 C#。 - user1097772
如果您知道可以丢弃对象,那么将其丢弃绝不是一个坏主意。 :-) 请注意,最好按照以下指令顺序执行:list[x].Dispose(); list.RemoveAt(x); - Thorsten Dittmar

7
该列表管理的是索引而不是对象。 因此,在执行memory.RemoveAt(0)后,列表中的第一个对象(以前在索引1处)现在将位于索引0处,并且计数自动减少为19。

2

哇,我不敢相信你们这些人把这件事情弄得那么复杂。OP想要的正是他所描述的,只要他按照所述去做就可以了。

Memory.RemoveAt(0);
Memory.Add(myBmp);

所有位图索引将减少1,新的位图将放置在第20个槽位的末尾。


返回翻译后的文本:是的。不过他把问题标记为“作业”,所以解释一下为什么事情会这样工作起来也不会太糟糕;-) - Thorsten Dittmar

0
我注意到在List中有这样一种行为,当你不断添加元素时,它会按照递增的索引添加项目。但是,如果你删除一个项目List.Remove(i)(i可以是任何索引),然后尝试添加List.Add(j),那么j项将被添加到堆栈顶部。这意味着j的索引为0。

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