C#重要集合类:列表、字典、队列、栈
主要内容:
重要集合类:列表、字典、队列、栈
- Timer定时器,Thread线程)
- 集合类:ArrayList、List列表、
- 集合类:Dictionary字典、
- 集合类:Queue队列、Stack栈
Timer定时器
Timer定时器:每间隔一段时间执行相同的业务逻辑,类似于循环。
定时器在C#中有两种:
-
线程安全的定时器
-
定时器控件(类)
public sealed class Timer : MarshalByRefObject, IDisposable//定时器是一个密封类。
{
...
public Timer(TimerCallback callback, object state, int dueTime, int period)
{
...
}
...
}
//回调函数
using System.Runtime.InteropServices;
namespace System.Threading;
[ComVisible(true)]
[__DynamicallyInvokable]
public delegate void TimerCallback(object state); //委托
#if false // 反编译日志
缓存中的 9 项
#endif
static void Main(string[] args)
{
//System.Threading.Timer定时器对象,线程安全的定时器对象。定时器能在间隔一段时间后循环调用某个回调函数。
//参数1:回调函数。参数2:向回调函数中传递的参数。定时器启动回头调用的方法。
//参数3:调用回调函数延迟的时间,单位:毫秒,0不迟,立即执行。
//参数4:每间隔多少毫秒执行一次回调函数。1000毫秒=1秒
//System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(TimerProc), null, 0, 1000)
System.Threading.Timer timer = new System.Threading.Timer(TimerProc, null, 0, 1000); //一个方法如果满足委托,直接写成方法名就行。
string input = Console.ReadLine(); //在主线程上执行等待用户的输入,不影响打印时间的运行。
Console.ReadKey();
}
//方法满足委托:1. 方法返回值和委托返回值类型一致 2.方法参数个数、类型、顺序和委托一样
static void TimerProc(object abc) //分线程,线程安全的定时器
{
Console.Clear();
//string input = Console.ReadLine(); //阻塞
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
//另一种Timer的实现方法
static void Main(string[] args)
{
Console.Title = "时钟";
Console.ForegroundColor = ConsoleColor.Red;
//写在主线程里,不安全的定时器,在控制台里面不会阻塞主线程,在winform里会阻塞。 定时器实例化
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000; //等待的时间,单位:毫秒,默认100毫秒,double类型
timer.Elapsed += Timer_Elapsed; //事件:被动触发的,语言程序执行的逻辑。闪电图标,委托皮包。
//定时器启动
timer.Start();
string input = Console.ReadLine();
if(input == 1)
{
Console.WriteLine("--------------"); //打印不出来,线程阻塞了。
}
Console.ReadKey();
}
//sender发送者,谁触发了事件(目标),事件句柄
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.Clear();
Console.WriteLine("选择功能项:【1】暂停【2】启动");
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
//运行
static void Main(string[] args)
{
Console.WriteLine("选择功能项:【1】暂停【2】启动");
string input = Console.ReadLine();
if(input == 1)
{
Console.WriteLine("--------------");
}
else
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
Console.ReadKey();
}
private static void Timer_Elapsed(object sender, System.Timers.ElapsedEvenArgs e)
{
Console.Clear();
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
}
Thread线程
static void Main(string[] args)
{
Console.Title = "电子时钟"; //设置窗口标题和长度
// Thread线程,线程在运行比较复杂的任务时,不会阻塞主线程的执行。
Thread timeThread = new Thread(new ThreadStart(Process));
timeThread.Start();
Console.ReadKey(true);
timeThread.Abort(); // 线程中止
}
//处理线程
static void Process()
{
// 死循环
while (true)
{
Console.Clear();
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
Thread.Sleep(1000); // 线程睡1秒,延迟1秒
}
}
分线程里死循环用的比较多,不影响主线程。
任务Task管理线程比Thread更灵活一点。
数组ArrayList
数组和集合概念,以及它们的区别:
- 数组【一般是相同数据类型】(object[]数组元素类型可以不同)的元素按一定顺序排列的集合。
- 数组在添加,插入,删除不方便。说明数组不是链表。
- 数组是集合,集合不一定是数组。Collection
- 数组读取(查询)速度比集合快。集合是线性表,在插入,添加,删除数据时比较方便,性能比数组会高。
- 数组存储的类型不限制。集合存储的类型只能是引用类型。
C#中的集合(Collection)和数组(Array)是两种不同的数据结构,它们之间有以下主要区别:
- 定义方式不同:集合是使用集合类定义的,如List或HashSet。数组是使用类型和大小显式定义的。
- 大小不同:数组的大小在创建后无法更改,而集合的大小可以根据需要动态增长。
- 内存布局不同:数组在内存中是连续的,而集合通常不是。
- 性能不同:访问数组元素通常比访问集合元素快,因为集合元素访问时可能需要进行装箱和拆箱操作。
- 索引访问:数组可以通过索引直接访问元素,而集合则需要使用迭代器或者在.NET 2.0及以上版本中使用foreach循环。
- 数据类型不同:数组可以存储基本数据类型(值类型),也可以存储引用类型,【而集合只能存储引用类型】,因为它们都继承自System.Object。
static void Main(string[] args)
{
//public class ArrayList : IList, ICollection, IEnumerable, ICloneable
//Iist列表 ICollection集合,IEnumerable可枚举,可迭代,可循环,ICloneable 可克隆,可复制
ArrayList arrayList1 = new ArrayList(); // 没有指定容量(常用)
ArrayList arrayList2 = new ArrayList(3); // 指定容量,提醒:没有存储任何的项,Count还是0
ArrayList arrayList3 = new ArrayList(new int[] { 1, 2, 3 });// 放一个实现ICollection接口的集合
// 1。添加,注意装箱,支持多种数据类型,取值时要拆箱,
arrayList1.Add(1);
arrayList1.Add("abc");
arrayList1.Add(true);
// Rang范围,一次添加多个
arrayList1.AddRange(new object[] { "hello", false, 20, 10, 20, 30, 40, 50, 60, 70, 80 });
arrayList1.AddRange(new List<int> { 1, 2, 3 });
arrayList1.AddRange(new Dictionary<string, string>() {
{ "key1","value1"},
{ "key2", "value2" }
});
// 2。清空
//arrayList1.Clear();
// 3。删除一个
//arrayList1.Remove("abc"); // 按值删除
//arrayList1.RemoveAt(0); // 按索引删除,有可能索引越界
//arrayList1.RemoveRange(0, 2);
// 4。取值
Console.WriteLine(arrayList1[0]);
Console.WriteLine(arrayList1[1]);
Console.WriteLine(arrayList1[2]);
KeyValuePair<string, string> keyValuePair = (KeyValuePair<string, string>)arrayList1[arrayList1.Count - 1];
Console.WriteLine($"key:{keyValuePair.Key},value:{keyValuePair.Value}");
Console.WriteLine("----------------");
//Console.WriteLine(arrayList2[1]); // 只有容量,没有存储项,索引越界
// 5。取数量
Console.WriteLine($"容量:{arrayList1.Capacity},数量:{arrayList1.Count}"); // Array.Length,集合的长度,集合中项的个数
Console.WriteLine(arrayList2.Count);
Console.WriteLine(arrayList3.Count);
// 6。如下属性和方法了解:
Console.WriteLine(arrayList1.IsReadOnly);// 是否只读
Console.WriteLine(arrayList1.IsFixedSize);// 是否固定大小,
ArrayList newArrayList = ArrayList.FixedSize(arrayList2); // FixedSize()固定大小
Console.WriteLine(newArrayList.IsFixedSize);// 是否固定大小,
Console.WriteLine(arrayList1.IsSynchronized);// 是否同步(少用)
// 7。取容量
// Capacity != Count,Capacity 是 可以存储的元素 ArrayList 数。 Count 是 中实际 ArrayList包含的元素数。
// Capacity 始终大于或等于 Count。 结论:Add和AddRange在给ArrayList扩容的机制不太一样。
// Add()扩容机制:2的次冥
Console.WriteLine(arrayList2.Capacity);
Console.WriteLine(arrayList3.Capacity);
// 8。复制(了解)
// 浅复制,装箱的操作,复制的源(原始的)和复制对象(新的)之间不会相互影响。
ArrayList arr1 = (ArrayList)arrayList1.Clone();
// ArrayList arr1 = arrayList1; // 会相互影响。
arrayList1.Add(20);
arr1.Add(40);
Console.WriteLine(arr1[arr1.Count - 1]);
Console.WriteLine(arrayList1[arrayList1.Count - 1]);
// 9。判断是否包含某项 返回布尔值
Console.WriteLine(arrayList1.Contains(200));
// 10。查索引,和string查索引一样规律。
Console.WriteLine(arrayList1.IndexOf(1)); // 0
Console.WriteLine(arrayList1.IndexOf("abc")); // 1
Console.WriteLine(arrayList1.IndexOf(200)); // -1
Console.WriteLine(arrayList1.LastIndexOf(1)); // 0
Console.WriteLine(arrayList1.LastIndexOf("abc")); // 1
Console.WriteLine(arrayList1.LastIndexOf(200)); // -1
// 11。插入
arrayList1.Insert(0, 2); // 在某个索引前插入一项
arrayList1.InsertRange(0, new char[] { 'a', 'b' });
Console.WriteLine(arrayList1[0]);
// this[]
// IEnumerator enumerator= arrayList1.GetEnumerator();
// enumerator.MoveNext();
Console.WriteLine("----------------------------------------");
// 12。循环, for,while,foreach, Array.ForEach()
/*Array.ForEach(arrayList1.ToArray(), (item) => {
Console.WriteLine(item);
});*/
foreach (var item in arrayList1)
{
Console.WriteLine(item);
}
// 13。集合查询,需要借助数组
// ToArray()转成数组
object[] obj2 = Array.FindAll(arrayList1.ToArray(), (item) =>
{
bool flag = IsNumeric(item.ToString());
if (flag)
{
int num = int.Parse(item.ToString());
if (num >= 10 && num <= 50)
{
return true;
}
}
return false;
});
ArrayList arr3 = new ArrayList(obj2); // 把数组再转换成ArrayList
// 14。反转和排序
//arrayList1.Reverse(); // 反转集合中项的顺序,会影响原集合
//arrayList1.Sort();
List<int> ints = new List<int>() { 10,20,30};
ArrayList.Adapter(ints); // 适配器:把实现IList接口的其他对象转换成ArrayList
Console.ReadKey();
}
public static bool IsNumeric(string str)
{
Regex regex = new Regex("^[0-9]+$");
return regex.IsMatch(str);
}
列表List
- 列表List对象,也是集合,并且是最流行的集合。
- List列表中的数据类型是统一的。
- List
整体是一个类型,由泛型和列表组成的复合类型,也称泛型列表。List也是类型,int也是类型, 表示未知类型。 - 泛型就是让这个列表支持多种类型。
- 泛型列表和ArrayList集合最大区别:List列表中的项类型是统一的,而ArrayList集合中的项类型可以不同。
// 比较器前提:实现
public class ListCompare : IComparer<Student>
{
public int Compare(Student x, Student y)
{
/* if (x.Id == y.Id)
{
return 0;
}
else
{
if (x.Id > y.Id)
{
return -1;
}
else
{
return 1;
}
}*/
return x.Name.CompareTo(y.Name);
}
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return $"编号:{Id},名称:{Name}";
}
}
static void Main(string[] args)
{
// 列表List对象,也是集合,并且是最流行集合
// List列表中的数据类型是统一的
// List<int>整体是一个类型,复合类型,List也是类型,int也是类型 <T>表示未知类型
// 也称泛型列表。和ArrayList集合最大区别:List列表中的项类型是统一的,而ArrayList集合中的项类型可以不同。
List<int> list1 = new List<int>() { 1,1,1};
List<string> list2 = new List<string>() { "abc" };
Student one = new Student() { Id = 1, Name = "张三1" };
List<Student> student1 = new List<Student>() {
one,
new Student(){ Id=2,Name="张三1"},
new Student(){ Id=3,Name="张三2"},
};
// 查询, 修改:(增,删,插)
// 1。查询数据:FindAll()正向查多项,Find()正向查一项,FindLast()倒查一项
List<Student> stus = student1.FindAll(stu => stu.Name == "张三1");
Student stu1 = student1.Find(stu => stu.Name == "张三1");
Student stu2 = student1.FindLast(stu => stu.Name == "张三1");
Console.WriteLine(stu1.Id);
Console.WriteLine(stu2.Id);
Console.WriteLine("--------------------------------");
// 2。查索引 IndexOf(), LastIndexOf(), FindIndex(), FindLastIndex()
int index1 = student1.IndexOf(one);//0
int index2 = student1.IndexOf(new Student() { Id = 1, Name = "张三1" });//-1
int index3 = student1.FindIndex(stu => stu.Id == 2);
Console.WriteLine(index1); // 0
Console.WriteLine(index2); // -1
Console.WriteLine(index3); // 1
// 3。添加
student1.Add(new Student() { Id = 3, Name = "李四" });
student1.AddRange(
new Student[]
{
new Student(){ Id = 4, Name = "李四1"},
new Student(){ Id = 5, Name = "李四2"},
});
student1.Sort(new ListCompare());
student1.ForEach(student =>
{
Console.WriteLine(student);
});
Console.WriteLine("--------------------");
foreach (var item in student1)
{
Console.WriteLine(item);
}
List<object> strList = student1.ConvertAll<object>((stu) =>
{
return new { Name = stu.Name, Age = stu.Age };
});
//student1.Clear();// 清空,没有任何条件
//student1.RemoveAll(stu => stu.Id < 2); // 满足条件删除
student1.InsertRange(0, new Student[] {
new Student(){ Id = 6, Name = "王五1"},
new Student(){ Id = 7, Name = "王五2"},
});
Dictionary<string, string> dict = new Dictionary<string, string>() {
{ "key1", "value1"},
{ "key2", "value2"},
};
dict.Add("key3", "value3"); // key不能重复
// KeyValuePair<string,string>可以var替代
foreach (KeyValuePair<string,string> item in dict)
{
// item是一个键值对
Console.WriteLine($"{item.Key}, {item.Value}");
}
// 想保存在线用户,Array,ArrayList,List,Dictionary
Console.WriteLine("----------------");
var keys = dict.Keys; // Keys是所有的键组成的集合。Values所有的值组成的集合。
foreach (var item in keys)
{
Console.WriteLine(item);
}
Queue queue = new Queue();
queue.Enqueue(1);
queue.Enqueue("你好");
queue.Enqueue(true);
queue.Enqueue(6.5);
Console.WriteLine(queue.Count);
object obj = queue.Dequeue();
Console.WriteLine(obj);
Console.WriteLine(queue.Count);
foreach (var item in queue)
{
Console.WriteLine(item);
}
HashSet<int> hs = new HashSet<int>() { 1, 2, 3,1 };
Console.ReadKey();
}
重要接口:
public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
数组实现了6个接口,前4个接口很重要
- ICloneable接口控制克隆,复制对象
- IList列表接口,控制对象操作(添加,删除等)
- IEnumerable可枚举对象的接口,控制是对象的循环
- ICollection集合接口,控制复制对象
-
public interface IList : ICollection, IEnumerable 说明列表也是集合的一种。
-
public class ArrayList : IList, ICollection, IEnumerable, ICloneable
-
public class List
: IList , ICollection , IEnumerable , IEnumerable, IList, ICollection, IReadOnlyList , IReadOnlyCollection
集合和列表的对比:
在C#中,List
List
HashSet
数组,列表都是集合。
数组不支持泛型,数组元素数据类型可以相同,也可不相同。而列表支持泛型,元素数据类型相同。
数组元素有序,列表元素也有序。
集合中元素可以有序,也可以无序。
迭代器,生成器(索引器):
迭代器:一个对象能循环,靠的是对象拥有迭代器。
谁来创造(生成)迭代器,生成器(索引器)来生成迭代器。
C#中生成器,叫成索引器。