目录
本篇文章来学习一下集合,C#集合主要分为非泛型集合与泛型集合。
集合
集合(Collection)是一种用于存储、管理和操作一组数据的容器或数据结构。在编程中,集合通常指的是能够存储多个元素的数据结构,它允许对元素进行各种操作,比如添加、删除、查找、排序、遍历等。集合可以是有序的,也可以是无序的,元素的类型可以是基本数据类型,也可以是对象。
集合是一种数据结构,一种数据容器。集合大小可变,空间不一定连续;分为非泛型集合(ArrayList)、泛型集合(列表(List)、字典 (Dictionary)、栈 (Stack) 、队列 (Queue)、哈希集合(HashSet))。
1.集合分类
1.1.非泛型集合
非泛型集合使用object类型来存储所有元素,可以将任何类型的对象放入集合中,但在取出元素时需要进行强制类型转换,这可能导致InvalidCastException等运行时错误,有时候需要手动转换类型。它们存储的元素通常是object类型,因此可以存储任何类型的数据。常见的非泛型集合包括ArrayList、Hashtable、Queue、Stack等。使用命名空间System.Collections。
特点:由于存储的元素是object类型,可能需要类型转换,运行时性能较差。
cs
using System.Collections;
using UnityEngine;
/// <summary>
/// ArrayList
/// </summary>
public class ArrayListTest
{
private ArrayList list = new ArrayList();//非泛型集合
private GameObject cube;
private void Start()
{
list.Add(1);
list.Add("张三");
list.Add("李四");
list.Add(cube);
//判断集合中是否含有"张三",并将"张三"移除
if (list.Contains("张三"))
list.Remove("张三");
//从索引1位置插入"王五"元素
list.Insert(1, "王五");
//从索引0位置移除2个元素
list.RemoveRange(0, 2);
for (int i = 0; i < list.Count; i++)
{
Debug.Log(list[i]);//有序输出
}
}
}
1.2.泛型集合
泛型集合是通过使用泛型类型参数T来提供类型安全的集合类型。常见的泛型集合包括List<T>、Dictionary<TKey, TValue>、Queue<T>、Stack<T>、HashSet<T>等。使用命名空间System.Collections.Generic。
1)列表(List)
List<T>是C#中最常用的集合类型之一,它是一个动态数组,允许在运行时添加、删除、修改元素,大小是可变的。
特点:动态大小,可以在运行时动态增减元素;支持随机访问,可以通过索引访问列表中的元素。
cs
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// List<T>
/// </summary>
public class ListTest
{
private List<string> strList = new List<string>();//泛型集合(需指定类型)
private List<int> intList = new List<int>() { 1, 10, 5, 100 };
private void Start()
{
strList.Add("张三");
strList.Add("李四");
strList.Add("王五");
strList.Add("赵六");
strList.Remove("李四");
foreach (var item in strList)
{
Debug.Log(item + " ");
}
intList.Sort();
foreach (var item in intList)
{
Debug.Log(item + " ");
}
}
}
2)字典(Dictionary)
Dictionary<TKey, TValue>是一个基于键-值对的集合,存储的每个元素都有一个唯一的键与对应的值。
特点:键值对,每个元素都有一个唯一的键,值是与键相对应的数据;快速查找,通过键可以快速查找到对应的值。
cs
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 字典(字典嵌套字典) Dictionary<TKey,TValue>
/// </summary>
public class DicTest : MonoBehaviour
{
//主键 子键 值
private Dictionary<string, Dictionary<string, string>> myDic
= new Dictionary<string, Dictionary<string, string>>();
private void Start()
{
//姓名 QQ 地址
myDic.Add("张三", new Dictionary<string, string>());
myDic["张三"].Add("QQ", "12345");
myDic["张三"].Add("地址", "北京");
print(myDic["张三"]["地址"]);//获取值
}
}
3)队列(Queue)
Queue<T>是一个先进先出(FIFO,First In First Out)的集合。它常用于实现排队的场景,比如任务调度、打印队列等。
特点:先进先出,队列中的元素按照它们被添加的顺序处理;添加操作(Enqueue)向队列的末尾添加元素,移除操作(Dequeue)从队列的前端移除元素。
cs
using UnityEngine;
using System.Collections;
/// <summary>
/// 队列Queue (先进先出) Queue<T>
/// </summary>
public class QueueTest : MonoBehaviour
{
private Queue queue = new Queue();
private void Start()
{
queue.Enqueue("入队");
print(queue.Dequeue());//移除并读队首
print(queue.Peek());//读取队首但不移除
print(queue.Count);
}
}
4)栈(Stack)
Stack<T> 是一个后进先出(LIFO,Last In First Out)的集合。它用于管理临时数据,如递归操作、回退功能等。
特点:后进先出,栈中的元素按照它们被添加的顺序的相反顺序被处理;添加操作(Push)将元素压入栈顶,移除操作(Pop)将栈顶元素弹出。
cs
using UnityEngine;
using System.Collections;
/// <summary>
/// 栈Stack (后进先出) Stack<T>
/// </summary>
public class StackTest : MonoBehaviour
{
/*
*主菜单->选项->游戏选项->难度调节->简单
*逐层压栈,逐层弹栈,最后一个(主菜单),只读不弹
*/
private Stack stack = new Stack();
private void Start()
{
//逐层压栈
stack.Push("主菜单");
stack.Push("选项");
stack.Push("游戏选项");
stack.Push("难度调节");
stack.Push("简单");
//逐层弹栈,读取用while
while (stack.Count > 1)
{
print("弹栈 : " + stack.Pop());
}
print("只读不弹 : " + stack.Peek());
}
}
5)哈希集合(HashSet)
HashSet<T> 是一个无序的集合,它存储唯一的元素,不允许有重复元素。
特点:无序,元素的顺序不是固定的;唯一性,不会允许添加重复的元素。
cs
HashSet<int> uniqueNumbers = new HashSet<int> { 1, 2, 3, 4, 4 };//4会被去重
2.集合的常见操作
1)添加元素:大多数集合类型都提供Add或类似的方法来添加元素。
2)删除元素:可以通过Remove、RemoveAt或Dequeue等方法来删除元素。
3)查找元素:可以使用Contains、IndexOf或通过键在字典中查找元素。
4)遍历元素:大多数集合都支持通过foreach或索引来遍历其中的元素。
5)清空集合:有些集合提供了Clear方法,用于清空集合中的所有元素。
3.区分泛型集合与非泛型集合
3.1.非泛型集合
1)优点
①灵活性高:非泛型集合可以存储不同类型的数据,因为它们是基于object类型的。例如,一个ArrayList可以存储 int、string、double等不同类型的对象,对于动态数据类型处理很有用。
cs
ArrayList list = new ArrayList();
list.Add(1);//添加int类型
list.Add("hello");//添加string类型
list.Add(3.14);//添加double类型
②向后兼容:非泛型集合是C#早期版本的标准,因此在一些老旧的代码库或库中,非泛型集合仍然被广泛使用。如果需要与旧版代码兼容,非泛型集合可能更方便。
③动态类型支持:非泛型集合对不同类型的数据支持更加灵活,适合动态类型的需求。例如,反射和序列化场景中,可能不清楚对象的确切类型时,使用object类型的集合会更方便。
2)缺点
①类型安全差:由于集合元素存储为object类型,因此无法保证集合中元素的类型一致性,所以必须在操作集合时进行类型检查和强制类型转换,以避免在运行时发生错误。
cs
ArrayList list = new ArrayList();
list.Add(1);//存储int类型
list.Add("hello");//存储string类型
//强制类型转换可能导致错误
int number = (int)list[1];//运行时错误:无法将string转换为int
②性能较差:由于元素存储为object类型,在访问时需要进行装箱(对于值类型)或类型转换。这些操作增加了运行时的开销,尤其是在处理大量数据时,性能会有所下降。
③无法直接使用LINQ:非泛型集合不直接支持LINQ查询。虽然可以将其转换为泛型集合来使用LINQ,但这样会增加额外的开销。
④维护难度大:如果集合中存储的元素类型不同,代码的可读性和维护性会变差。因此必须记住集合中包含哪些类型,避免发生类型转换错误。
3.2.泛型集合
1)优点
①类型安全:泛型集合允许在编译时指定元素类型,保证集合中的元素类型一致。这避免了运行时类型转换错误,提高了代码的安全性。如,List<int>只能存储int类型的元素,不会出现类型不匹配的错误。
cs
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
//numbers.Add("string");//编译时错误,不能将string添加到List<int>中
②性能优越:由于泛型集合在编译时确定元素类型,不需要进行类型转换或装箱操作,因此性能通常更好。对于值类型(如 int、struct等),没有装箱过程,因此可以避免额外的内存开销。
③可读性和维护性:泛型集合提高了代码的可读性和可维护性,因为明确知道集合中的元素类型,代码更加直观。
④支持LINQ查询:泛型集合与LINQ查询集成得很好,能够直接进行类型安全的查询和操作。
2)缺点
①类型限制:泛型集合要求指定集合元素的类型,这可能导致在一些动态类型的场景中,使用泛型集合不太方便。如在处理不同类型的对象时可能需要使用object类型(这就绕回到非泛型集合的做法)。
②开发复杂度:如果需要存储不同类型的数据,可以通过object类型的泛型集合来实现,但这可能导致类型转换的麻烦,降低了类型安全。
总结
1)泛型集合:当需要高性能、类型安全、并且处理明确类型的数据时,应该选择泛型集合。
2)非泛型集合:当需要处理不同类型的数据(如存储不同类型的对象)或者与旧版代码兼容时,选择非泛型集合。
|-------------|---------------------|----------------------|
| 特性 | 泛型集合 | 非泛型集合 |
| 类型安全 | 强制指定元素类型,编译时类型检查 | 使用Object类型,缺乏类型安全 |
| 性能 | 更高,避免装箱和类型转换 | 较低,需要装箱和类型转换 |
| 灵活性 | 只能存储指定类型的元素 | 可以存储任何类型的元素 |
| 开发复杂度 | 需要指定元素类型,适用于类型明确的场景 | 可存储不同类型的数据,适用于动态类型场景 |
| 兼容性 | 现代C#项目,广泛使用 | 向后兼容旧版C#代码,支持更动态的需求 |
| 支持 LINQ | 支持LINQ查询 | 不直接支持LINQ查询 |
泛型集合的类型更安全、性能更高,在C#的大多数开发中,更推荐使用泛型集合。而非泛型集合由于灵活性更高,适合存储多种类型的数据,但因类型安全差,性能较低,需谨慎使用。
好了,今天的分享到这里就结束啦,希望对你有所帮助~