.NET Core CSharp 中级篇 2-2
本节内容为 List,ArrayList, 和 Dictionary
简介
在此前的文章中我们学习了数组的使用, 但是数组有一个很大的问题就是存储空间不足, 我们通常的解决方法就是定义一个绝对够用的数组, 这通常很大, 但是这样就造成了内存的损失. 我们总是希望有一个根据需求动态更变的数组进行存储. 在上一节中的综合题中已经隐隐约约引出了 List 的概念. 这一讲我们会详细的讲解 List.
同时, 有时候我们希望数组不单单的存储我们的数据. 例如我希望有那么一些数据:
某人的成绩单如下:
语文 80 分
数学 90 分
英语 87 分
对于这些数据, 我们使用数组并不能很好的反馈这些成绩, 这个时候我们需要使用我们的字典进行存储.
- List,ArrayList
- ArrayList
正如上文所言, 数组是一段连续存储空间, 访问速度非常快, 但是必须指定大小, 这个时候我们可以使用 ArrayList 进行使用. ArrayList 是位于 System.Collections 的一个类, 继承与 IList 接口, 提供了数据的操作. 它比数组更优的地方是, 它不需要指定任何的大小和类型, 直接使用即可.
- ArrayList al = new ArrayList();
- al.Add("test");
- al.Add(1234);
- // 修改数据
- al[1] = 4;
- // 移除数据
- al.RemoveAt(0);
- // 插入数据
- al.Insert(0, "qwe");
看起来非常好用对吧, 可以插入不同数据并且修改. 但是其实这是非常损失性能的一个操作. 因为在 ArrayList 中插入不同类型的数据是是允许的, 但是在处理后续数据的时候, ArrayList 会将内部所有的数据当成 Object 类型进行处理, 因此在每一个数据进行遍历的时候, 都会发生装箱与拆箱的操作, 在上一讲我们讨论过, 频繁的装拆箱是极其损耗性能的. 因此, ArrayList 在实际情况下并不经常使用.
泛型 List
为了解决 ArrayList 中类型不同导致的不安全和装拆箱, 我们使用泛型 List 类. List 类是 ArrayList 类的泛型等效类, 它的大部分用法都与 ArrayList 相似, 因为 List 类也继承了 IList 接口. 最关键的区别在于, 在声明 List 集合时, 我们同时需要为其声明 List 集合内数据的对象类型, 也就是泛型参数. 我们在
初级篇的综合习题中已经隐约引出了关于 List 的部分内容. 对于 List, 它的定义如下:
- List<T> list = new List<T>();
- list.Add(new T());
- list[0];
- list.Remove(T);
对于 List, 它实现了一个非常重要的接口 --IEnumerable, 这意味着 List 支持使用 foreach 循环进行遍历内部元素. 不过使用 foreach 的时候, 下列操作时不合法的:
- foreach(var item in MyList)
- {
- MyList.Remove(item);// 不过我相信没有人那么干, 但是....
- // 这种操作我不止一次见过有人问我
- if(item.something == something)
- {
- MyList.Remove(item);
- }
- }
这个时候, 你需要往回仔细的回忆我们之前 foreach 循环的讲解, 在 foreach 循环中通过这种方式动态的删除一个元素是不合法的, 为什么? 因为 foreach 循环会调用 MoveNext()方法, 你可以想象一下一个节点连着一个节点成为了一串集合体, 你每次只能向后访问一个节点, 也就意味着你必须知晓前一个节点才可以访问后一个节点, 假设你访问到某节点的时候, 你删除了它, 那么后续的节点访问都无法被访问. 有没有解决的方法呢? 当然有, 但是你只能使用 for 循环, List 中有一个属性叫做 Count, 这个代表着当前 List 中所拥有的所有元素的个数, 并且 List 实现了索引器, 也就是说, List 可以通过类似于 MyList[0]的方式访问, 这个时候, 你使用 for 循环动态删除应当如下:
- for(int i =0;i<MyList.Count;i++)
- {
- if(MyList[i].something == something)
- {
- MyList.Remove(MyList[i]);
- }
- }
Dictionary 字典
你肯定有过简介中提到过的需求. 很多时候单纯的索引值没有办法给我们提供更多的信息, 我们总是倾向于使用一个键值对的方式进行存储数据. 那么 Dictionary 将会很好的解决你的问题. 它的基本结构是由两个泛型参数进行修饰, Dictionary<TKey,TValue>, 前面是键的类型, 后面是值的类型, 你也可以把 Dictionary 理解成一种特殊的集合. 它的使用如下:
- Dictionary<string,string> dict = new Dictionary<string,string>();
- dict.Add("广东","广州");
- dict.Add("江西","南昌");
- dict["江西"];
- dict.remove("广东");
通常来说, 我们很少使用 foreach 直接访问 Dictionary, 因为迭代的结果就是一个个键值对, 一般 Dictionary 的 Value 以 List 居多, 因此一般都是迭代 Key.
Dictionary 大部分操作和 List 是接近的, 这里就不过多阐述.
IEnumerable 与 IList 接口
这两个接口时集合 (List) 的实现的重要接口, IEnumerable 提供了迭代功能, IList 提供了相应的集合操作, 我们从元数据中就可以很好的学习他们.
IEnumerable 接口
它在元数据的定义如下:
- public interface IEnumerable<out T> : IEnumerable
- {
- //
- // 摘要:
- // Returns an enumerator that iterates through the collection.
- //
- // 返回结果:
- // An enumerator that can be used to iterate through the collection.
- IEnumerator<T> GetEnumerator();
- }
我们可以很清楚的发现泛型参数中有 out 关键字修饰, 也就是说, 我们的 IEnumerable 是支持协变的. 我们可以很轻松的将 IEnumerable 类型的数据转换成其他数据, 例如:
- IEnumerable<string> strs = new IEnumerable<string>();
- IEnumerable<object> obj = strs;
因此我通常在使用的时候, 我会推荐使用 IEnumerable 来代替 List 的一些数据操作.
IList 接口
老规矩, 先看看元数据
- public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
- {
- // 省略
- }
这里就可以发现 IList 并不支持协变, 属于不变式, 那么下列用法是不合法的:
- IList<string> strs = new IList<string>();
- IList<object> obj = strs;
如果我的文章帮助了您, 请您在 GitHub .NET Core Guide 项目帮我点一个 star, 在博客园中点一个关注和推荐.
GitHub https://github.com/StevenEco/.NetCoreGuide
BiliBili 主页 https://space.bilibili.com/33311288
WarrenRyan's Blog https://blog.tity.xyz/
博客园
来源: https://www.cnblogs.com/WarrenRyan/p/11294784.html