C#中List<T>存放元素的工作机制
作者:Darren?Ji 时间:2022-09-29 16:31:23
List<T>是怎么存放元素?我们扒一段List<T>的一段源码来一窥究竟。
using System;
using System.Diagnostic;
using System.Collections.ObjectModel;
using System.Security.Permissions;
namespace System.Collections.Generic
{
...
[Serializable()]
public class List<t> : IList<t>, System.Collections.IList
{
private const int _defaultCapacity = 4;
private T[] _items; //List<T>内部是依靠数组_items存放数据的
private int _size; //数组的长度
private int _version;
[NoSerialized]
private Object _syncRoot;
static T[] _emptyArray = new T[0];
//无参数构造函数 把_items设置成一个空的数组
public List()
{
_items = _emptyArray;
}
//此构造函数 给_items数组一个初始容量
public List(int capacity)
{
...
items = new T[capaicty];
}
//此构造函数 把集合类型参数拷贝给_items数组
public List(IEnumerable<t> collection)
{
...
ICollection<t> c = collection as ICollection<t>;
if(c != null)
{
int count = c.Count; //把构造函数集合类型参数的长度赋值给临时变量count
_items = new T[count]; //List<T>内部维护的_items数组的长度和构造函数集合类型参数的长度一致
c.CopyTo(_items, 0); //把构造函数集合的所有元素拷贝到_items数组中去
_size = count; //_items数组的长度就是构造函数集合类型参数的长度
}
else
{
_size = 0;
_items = new T[_defaultCapacity];
...
}
}
//通过设置这个属性,改变List<t>内部维护的_items数组的长度
public int Capacity
{
get {return _items.Length; }
set {
if(value != _items.Length){ //如果当前赋值和List<t>维护的内部数组_items长度不一致
if(value < _size){
//TODO: 处理异常
}
if(value > 0){
T[] newItems = new T[value]; //创建一个临时的、新的数组,长度为新的赋值
if(_size > 0){
//把临时的、新的数组拷贝给List<t>内部维护的数组_items,注意,这时_items的长度为新的赋值
Array.Copy(_items, 0, newItems, 0, _size);
}
} else {
_items = _emptyArray;
}
}
}
}
public void Add(T item)
{
if(_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
...
}
//确保List<t>内部维护的_items数组的长度至少是给定的值
//如果_items数组原先的长度比给定的值小,就让_items数组的长度设置为原先的长度的2倍
privat void EnsureCapacity(int min)
{
if(_items.Length < min){
int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Legnth * 2;
if(newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
}
}
}
由此可见,向List<T>中存放元素的大致过程是这样的:
List<T>内部维护着一个数组_items,用来存放T类型的元素。
当有新的T类型元素存放进来,即调用Add(T item)方法。
Add(T item)方法内部调用EnsureCapacity(int min)方法确保List<T>的Capaicty属性值至少在原先长度上加1,最多是原先长度的2倍。
在给Capacity赋值的过程中,对_items的长度进行了扩容。
扩容后,再把新的T类型元素存放进来。
简单地说:
当有新的元素存放到List<T>中时,List<T>先对其维护的内部数组进行扩容,然后再把新元素放进来。
来源:https://www.cnblogs.com/darrenji/p/3843749.html
标签:C#,List,存放,元素
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
JAVA操作MongoDB数据库实例教程
2023-11-18 13:22:27
springboot+jersey+tomcat实现跨域方式上传文件到服务器的方式
2023-08-16 10:26:45
![](https://img.aspxhome.com/file/2023/9/66679_0s.jpg)
java开发中遇到的异常汇总详解
2023-03-21 02:54:15
SpringBoot中Shiro缓存使用Redis、Ehcache的方法
2023-10-04 17:34:59
C# DateTime与时间戳转换实例
2022-12-12 08:34:12
Knife4j 3.0.3 整合SpringBoot 2.6.4的详细过程
2023-11-25 03:54:34
![](https://img.aspxhome.com/file/2023/9/59429_0s.png)
Spring Cloud + Nacos + Seata整合过程(分布式事务解决方案)
2021-08-31 04:26:52
![](https://img.aspxhome.com/file/2023/4/63734_0s.png)
mybatis-plus使用问题小结
2023-10-30 06:45:58
Android中资源文件用法简单示例
2023-09-24 22:29:04
C#实现Windows Form调用R进行绘图与显示的方法
2021-11-29 05:40:13
![](https://img.aspxhome.com/file/2023/0/81090_0s.jpg)
浅析C# 状态机Stateless
2022-03-08 16:39:07
Android 8.0如何完美适配全局dialog悬浮窗弹出
2023-04-09 12:54:00
![](https://img.aspxhome.com/file/2023/8/90138_0s.png)
深入Android MediaPlayer的使用方法详解
2023-07-21 21:50:47
手把手带你实现一个萌芽版的Spring容器
2023-03-10 15:45:44
![](https://img.aspxhome.com/file/2023/9/94759_0s.png)
SpringBoot使用注解进行分页的实现示例
2021-08-21 22:45:32
![](https://img.aspxhome.com/file/2023/3/75473_0s.jpg)
android Watchdog 实现剖析
2022-07-12 06:39:21
![](https://img.aspxhome.com/file/2023/3/98683_0s.jpg)
Java多线程与线程池技术分享
2021-07-25 07:35:11
![](https://img.aspxhome.com/file/2023/2/80322_0s.jpg)
IDEA内存调试插件(好用)
2022-04-19 08:51:13
![](https://img.aspxhome.com/file/2023/3/108413_0s.jpg)
Android实现登录界面的注册功能
2021-10-22 01:17:55
![](https://img.aspxhome.com/file/2023/3/106873_0s.jpg)
Android开发工程中集成mob短信验证码功能的方法
2022-12-15 06:37:02
![](https://img.aspxhome.com/file/2023/7/106807_0s.png)