向List预留位置插入元素时触发System.ArgumentOutOfRangeException异常
问题描述
我有一个List实例,它的Count是0但Capacity为2(当前没有元素,但已经预留了存储空间):
System.Diagnostics.Debug.WriteLine(paginationCollection.PagesContent.Count); // 0 System.Diagnostics.Debug.WriteLine(paginationCollection.PagesContent.Capacity); // 2
这个List属于PaginationCollection<Item>类的实例,类定义如下:
public class PaginationCollection<Item> { public readonly uint PagesCount; public List<List<Item>> PagesContent; public PaginationCollection( uint pagesCount, byte numerationFrom ) { PagesCount = pagesCount; PagesContent = new List<List<Item>>(numerationFrom == 0 ? (int)pagesCount : (int)pagesCount + 1); } }
当我尝试向位置1插入元素时,触发了System.ArgumentOutOfRangeException异常,插入代码如下:
for (int pageNumber = pagesNumerationFrom; pageNumber < lastPageNumber; pageNumber++) { paginationCollection.PagesContent.Insert( pageNumber, // 当前这个值是1 // 已经确认GetRange操作不会抛出异常 flatCollection.GetRange((int)elementStartingPositionForCurrentPage, (int)elementEndingPositionForCurrentPage) ); // ... }
从逻辑上看,位置1现在是空的,我以为C#里只要Capacity大于等于目标位置就能插入,为什么会触发这个异常?
问题原因与解决办法
核心误区:搞混了Count和Capacity的作用
C#里List<T>的Capacity只是底层数组已经分配的存储空间大小,和列表里实际有多少元素没关系。而Insert方法对插入位置的要求是:必须满足0 ≤ index ≤ Count,跟Capacity一点关系都没有。
当你的PagesContent.Count是0的时候,允许的插入位置只有0——空列表只能在最开头(位置0)插入元素。你现在要插去位置1,超出了当前Count的范围,自然就会抛出ArgumentOutOfRangeException。
两种解决思路
如果你的业务逻辑需要从位置1开始填充元素(比如页码从1开始编号),可以选下面两种方案:
- 先填占位元素:在构造
PagesContent之后,先添加足够数量的null或者空列表占位,让Count达到你需要的最大页码值。比如在构造函数最后加这段代码:
之后直接用索引赋值(// 填充到目标数量的空元素 while (PagesContent.Count < (numerationFrom == 0 ? (int)pagesCount : (int)pagesCount + 1)) { PagesContent.Add(null); }PagesContent[pageNumber] = ...)就行,不用再用Insert。 - 调整插入逻辑:如果不需要占位,直接用
Add方法添加元素,之后业务里用页码的时候,把业务页码转换成列表索引(比如业务页码1对应列表索引0)。
内容的提问来源于stack exchange,提问作者Takeshi Tokugawa YD
相关产品推荐
相关产品推荐

