基础语法(二)
数组
数组从字面上理解就是存放一组数,但在 C# 语言中数组存放的并不一定是数字,也可以是其他数据类型。
声明数组时,方括号[]
必须跟在类型后面,而不是标识符后面。
int[] table;
一维数组
一维数组在数组中最常用,即将一组值存放到一个数组中,并为其定义一个名称,通过数组中元素的位置来存取值。
数据类型[] 数组名;
数组的初始化有如下几种方式:
//初始化数组中的元素
数据类型[] 数组名 = new 数据类型[长度];
数据类型[] 数组名 = {值 1, 值 2, ...}
数据类型[] 数组名 = new 数据类型[长度]{值 1,值 2,...}
在定义数组时定义的数据类型代表了数组中每个元素的数据类型。
由于在数组中存放了多个元素,在存取数组中的元素时要使用下标来存取,类似于取字符串中的字符。
class Program {
static void Main(string[] args) {
//定义 int 类型的数组
int[] a = {1,2,3};
//输岀数组中的一个元素
Console.WriteLine(a[0]);
//输出数组中的最后一个元素
Console.WriteLine(a[a.Length-1]);
}
}
获取数组的长度使用的是数组的Length
属性,数组的下标仍然从 0 开始,数组中的最后一个元素是数组的长度减 1。
创建一个字符串类型的数组,并存入 5 个值,然后将数组中下标是偶数的元素输出。
class Program {
static void Main(string[] args) {
string[] strs = {"aaa", "bbb", "ccc", "ddd", "eee"};
for (int i = 0; i < strs.Length; i++) {
if (i % 2 == 0) {
Console.WriteLine(strs[i]);
}
}
}
}
创建 int 类型数组,并从控制台输入 5 个值存入该数组中,最后将数组中的最大数输出。
class Program {
static void Main(string[] args) {
int[] a = new int[5];
Console.WriteLine("请输入5个整数:");
for (int i = 0; i < a.Length; i++) {
a[i] = int.Parse(Console.ReadLine());
}
int max = a[0];
for (int i = 0; i < a.Length; i++) {
if (a[i] > max) {
max = a[i];
}
}
Console.WriteLine("数组中最大值为:{0}", max);
}
}
多维数组
在 C# 语言里多维数组中比较常用的是二维数组。
定义多维数组的语法形式如下:
数据类型[ , , ...] 数组名;
多维数组的初始化方式如下:
数据类型[ , , ...] 数组名 = new 数据类型[m,n,...] {{ , , ...},{ , , ...}};
存取数组中的值也是将下标用“,”隔开。
定义一个存放学生成绩的二维数组,并将该数组中每个学生的成绩输出。
class Program {
static void Main(string[] args) {
double[,] points = { {90, 80}, {100, 89}, {88.5, 86}};
for (int i = 0; i < points.GetLength(0); i++) {
Console.WriteLine("第" + (i + 1) + "个学生成绩:");
for (int j = 0; j < points.GetLength(1); j++) {
Console.Write(points[i, j] + " ");
}
Console.WriteLine();
}
}
}
在遍历多维数组元素时使用 GetLength(维度) 方法能获取多维数组中每一维的元素,维度也是从 0 开始的。
锯齿数组
C# 语言中不仅支持上面给出的多维数组,也支持锯齿型数组,即在多维数组中的每一维中所存放值的个数不同。
锯齿型数组也被称为数组中的数组。定义锯齿型数组的语法形式如下。
数据类型[][] 数组名 = new 数据类型[数组长度][];
数组名[0] = new 数据类型[数组长度];
在这里,数据类型指的是整个数组中元素的类型,在定义锯齿型数组时必须要指定维度。
创建一个锯齿型数组,第一维数组的长度是 2、第二维数组的长度是 3、第三维数组的长度是 4,并直接向数组中赋值,最后输出数组中的元素。
class Program {
static void Main(string[] args) {
int[][] arrays = new int[3][];
arrays[0] = new int[] {1, 2};
arrays[1] = new int[] {3, 4, 5};
arrays[2] = new int[] {6, 7, 8, 9};
for (int i = 0; i < arrays.Length; i++) {
Console.WriteLine("输出数组中第" + (i + 1) + "行的元素:");
for (int j = 0; j < arrays[i].Length; j++) {
Console.Write(arrays[i][j] + " ");
}
Console.WriteLine();
}
}
}
锯齿型数组中的值也可以通过循环语句来赋值,与输岀语句类似。
foreach语句
foreach 循环用于列举出集合中所有的元素,foreach 语句中的表达式由关键字 in 隔开的两个项组成。
foreach 语句经常与数组一起使用,在 C# 语言中提供了 foreach 语句遍历数组中的元素,具体的语法形式 如下:
foreach(数据类型 变量名 in 数组名) {
//语句块;
}
这里变量名的数据类型必须与数组的数据类型相兼容。
foreach 语句仅能用于数组、字符串或集合类数据类型。
class Program {
static void Main(string[] args) {
double[] points = {80, 88, 86, 90, 75.5};
double sum = 0;
double avg = 0;
foreach (double point in points) {
sum += point;
}
avg = sum / points.Length;
Console.WriteLine("总成绩为:{0}", sum);
Console.WriteLine("平均成绩为:{0}", avg);
}
}
Split切割
Split 方法用于按照指定的字符串来拆分原有字符串,并返回拆分后得到的字符串数组。
从控制台输入一个字符串,然后计算该字符串中包含的逗号的个数。
class Program {
static void Main(string[] args) {
Console.WriteLine("请输入一个字符串:");
string str = Console.ReadLine();
string[] strs = str.Split(",");
foreach (var s in strs) {
Console.Write(s + " ");
}
}
}
在使用 Split 方法时,需要注意该方法中传递的参数 (condition, StringSplitOptions.None)。
第一个参数:拆分的条件数组,可以在该数组中存放多个字符串作为拆分的条件。
第二个参数:StringSplitOptions.None 是拆分的选项,表示如果在拆分时遇到空字符也拆分出一个元素。
枚举类型
枚举类型和结构体类型都是特殊的值类型,应用也比较广泛。
枚举类型在定义时使用 enum 关键字表示,枚举类型的定义与类成员的定义是一样的,或者直接定义在命名空间中。
访问修饰符 enum 变量名 : 数据类型 {
值l,
值2,
}
修饰符:与类成员的访问修饰符一样,省略访问修饰符也是代表使用 private 修饰符的。
数据类型:指枚举中值的数据类型。只能是整数类型,包括 byte、short、int、long 等。
值:在枚举类型中显示的值。但实际上每个值都被自动赋予了一个整数类型值,并且值是递增加 1 的,默认是从 0 开始。
class Program {
public enum Season : int {
春天,
夏天,
秋天,
冬天
}
static void Main(string[] args) {
Console.WriteLine(Season.春天 + ":" + (int)Season.春天);
Console.WriteLine(Season.夏天 + ":" + (int)Season.夏天);
Console.WriteLine(Season.秋天 + ":" + (int)Season.秋天);
Console.WriteLine(Season.冬天 + ":" + (int)Season.冬天);
}
}
结构体类型
在结构体中能定义字段、属性、方法等成员。定义的语法形式如下:
访问修饰符 struct 结构体名称 {
// 结构体成员
}
访问修饰符:通常使用 public 或者省略不写,如果省略不写,代表使用 private 来修饰。
结构体名称:命名规则通常和变量的命名规则相同,即从第二个单词开始每个单词的首字母大写。
结构体成员:包括字段、属性、方法以及后面要介绍的事件等。
在结构体中也能编写构造器,但必须带参数,并且必须为结构体中的字段赋初值。
class Program {
public struct student {
private string name;
private int age;
public student(string name, int age) {
this.name = name;
this.age = age;
}
public void printStudent() {
Console.WriteLine("姓名:{0}", name);
Console.WriteLine("年龄:{0}", age);
}
}
static void Main(string[] args) {
student student = new student("李四", 25);
student.printStudent();
}
}
结构体与类有些类似,但其定义却有很大区别,具体如下表所示:
结构体 | 类 |
---|---|
允许不使用new对其实例化 | 必须使用new实例化 |
没有默认构造方法 | 有默认构造方法 |
不能继承类 | 能继承类 |
没有析构方法 | 有析构方法 |
不允许使用abstract、protected以及sealed修饰 | 允许使用abstract、protected以及sealed修饰 |
集合
集合与数组比较类似,都用于存放一组值,但集合中提供了特定的方法能直接操作集合中的数据,并提供了不同的集合类来实现特定的功能。
集合类或与集合相关的接口命名空间都是 System.Collection,该命名空间中提供的常用接口如下表所示。
接口名称 | 作用 |
---|---|
IEnumerable | 用于迭代集合中的项,该接口是一种声明式的接口 |
IEnumerator | 用于迭代集合中的项,该接口是一种实现式的接口 |
ICollection | .NET 提供的标准集合接口,所有的集合类都会直接或间接地实现这个接口 |
IList | 继承自 IEnumerable 和 ICollection 接口,用于提供集合的项列表,并允许访问、查找集合中的项 |
IDictionary | 继承自 IEnumerable 和 ICollection 接口,与 IList 接口提供的功能类似,但集 合中的项是以键值对的形式存取的 |
IDictionaryEnumerator | 用于迭代 IDictionary 接口类型的集合 |
针对上表中的接口有一些常用的接口实现类,如下表所示:
类名称 | 实现接口 | 特点 |
---|---|---|
ArrayList | ICollection、IList、IEnumerable、ICloneable | 集合中元素的个数是可变的,提供添加、删除等方法 |
Queue | ICollection、IEnumerable、ICloneable | 集合实现了先进先出的机制,即元素将在集合的尾部添加、在集合的头部移除 |
Stack | ICollection、IEnumerable、ICloneable | 集合实现了先进后出的机制,即元素将在集合的尾部添加、在集合的尾部移除 |
Hashtable | IDictionary、ICollection、IEnumerable、 ICloneable 等接口 | 集合中的元素是以键值对的形式存放的,是 DictionaryEntry 类型的 |
SortedList | IDictionary、ICollection、IEnumerable、 ICloneable 等接口 | 与 Hashtable 集合类似,集合中的元素以键值对的形式存放,不同的是该集合会按照 key 值自动对集合中的元素排序 |
ArrayList
ArrayList 类(动态数组)是一个最常用的集合类,与数组的操作方法也是最类似的。
ArrayList 代表了可被单独索引的对象的有序集合。它基本上可以替代一个数组。
构造方法 | 作用 |
---|---|
ArrayList() | 创建 ArrayList 的实例,集合的容量是默认初始容量 |
ArrayList(ICollection c) | 创建 ArrayList 的实例,该实例包含从指定实例中复制的元素,并且初始容量与复制的元素个数相同 |
ArrayList(int capacity) | 创建 ArrayList 的实例,并设置其初始容量 |
下面分别使用 ArrayList 类的构造器创建 ArrayList 实例,代码如下。
ArrayList listl=new ArrayList();
ArrayList list2=new ArrayList(listl);
ArrayList list3=new ArrayList(20);
在创建 ArrayList 类的实例后,集合中还未存放值。
在 C# 语言中提供了集合初始化器,允许在创建集合实例时向集合中添加元素,代码如下:
ArrayList list = new ArrayList(){1,2,3,4};
集合与数组一样也能使用 foreach 语句遍历元素。
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList(){1, 2, 3, 4};
foreach (var v in list) {
Console.WriteLine(v);
}
}
}
在 ArrayList 类中提供了很多属性和方法供开发人员调用,以便简化更多的操作。
ArrayList 类中常用的属性和方法如下表所示。
属性或方法 | 作用 |
---|---|
int Add(object value) | 向集合中添加 object 类型的元素,返回元素在集合中的下标 |
void AddRange(ICollection c) | 向集合中添加另一个集合 c |
Capacity | 属性,用于获取或设置集合中可以包含的元素个数 |
void Clear() | 从集合中移除所有元素 |
bool Contains(object item) | 判断集合中是否含有 item 元素,若含有该元素则返回 True, 否则返回 False |
void CopyTo(Array array) | 从目标数组 array 的第 0 个位置开始,将整个集合中的元素复制到类型兼容的数组 array 中 |
void CopyTo(Array array,int arraylndex) | 从目标数组 array 的指定索引 arraylndex 处,将整个集合中的元素赋值到类型兼容的数组 array 中 |
void CopyTo(int index,Array array,int arrayIndex,int count) | 从目标数组 array 的指定索引 arrayindex 处,将集合中从指定索引 index 开始的 count 个元素复制到类型兼容的数组 array 中 |
Count | 属性,用于获取集合中实际含有的元素个数 |
int IndexOf(object value) | 返回 value 值在集合中第一次出现的位置 |
int IndexOf(object value,int startIndex) | 返回 value 值在集合的 startindex 位置开始第一次出现的位置 |
int IndexOf(object value,int startIndex,int count) | 返回 value 值在集合的 startindex 位置开始 count 个元素中第一次出现的位置 |
int LastIndexOf(object value) | 返回 value 值在集合中最后一次出现的位置 |
int LastIndexOf(object value,int startIndex) | 返回 value 值在集合的 startindex 位置开始最后一次出现的位置 |
int LastIndexOf(object value,int startIndex,int count) | 入元素 value值在集合的 startindex 位置开始 count 个元素中最后一次出现的位置 |
void Insert(int index,object value) | 返回 value 向集合中的指定索引 index 处插 |
void InsertRange(int index,ICollection c) | 向集合中的指定索引 index 处插入一个集合 |
void Remove(object obj) | 将指定兀素 obj 从集合中移除 |
void RemoveAt(int index) | 移除集合中指定位置 index 处的元素 |
void RemoveRange(int index,int count) | 移除集合中从指定位置 index 处的 count 个元素 |
void Reverse() | 将集合中的元素顺序反转 |
void Reverse(int index,int count) | 将集合中从指定位置 index 处的 count 个元素反转 |
void Sort() | 将集合中的元素排序,默认从小到大排序 |
void Sort(IComparer comparer) | 将集合中的元素按照比较器 comparer 的方式排序 |
void Sort(int index,int count,IComparer comparer) | 将集合中的元素从指定位置 index 处的 count 个元素按照比较器 comparer 的方式排序 |
void TrimToSize() | 将集合的大小设置为集合中元素的实际个数 |
查找集合中的元素,使用 IndexOf 或者 LastlndexOf 都可以,代码如下。
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList() { "aaa", "bbb", "abc", 123, 456 };
int index = list.IndexOf("abc");
if (index != -1) {
Console.WriteLine("集合中存在 abc 元素!");
} else {
Console.WriteLine("集合中不存在 abc 元素!");
}
}
}
将集合中下标为偶数的元素添加到另一个集合中:
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList() { "aaa", "bbb", "abc", 123, 456 };
ArrayList newList = new ArrayList();
for(int i = 0; i < list.Count; i = i + 2) {
newList.Add(list[i]);
}
foreach(var v in newList) {
Console.WriteLine(v);
}
}
}
在集合中的第一个元素后面添加元素,使用 Insert 方法每次只能添加一个元素,但使用 InsertRange 方法能直接将一个集合插入到另一个集合中。
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList() { "aaa", "bbb", "abc", 123, 456 };
ArrayList insertList = new ArrayList() { "A", "B", "C" };
list.InsertRange(1, insertList);
foreach(var v in list) {
Console.WriteLine(v);
}
}
}
使用 Sort 方法对集合中的元素排序,则需要将集合中的元素转换为同一类型才能比较,否则会出现无法比较的异常。
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList() { "aaa", "bbb", "abc" };
list.Sort();
foreach(var v in list) {
Console.WriteLine(v);
}
}
}
默认是按照自然排序的顺序,如果需要比较字符串的值则需要使用CompareTo
方法。
字符串1.CompareTo(字符串2);
在 ArrayList 类中常用的属性和方法表中列出的 Sort 方法中,Sort 方法能传递 IComparer 类型的参数。
1)定义比较器,用于比较两个字符串
class MyCompare : IComparer {
public int Compare(object? x, object? y) {
string str1 = x.ToString();
string str2 = y.ToString();
return str1.CompareTo(str2);
}
}
2)在sort
方法中使用自定义的比较器进行比较:
class Program {
static void Main(string[] args) {
ArrayList list = new ArrayList() { "a", "b", "c", 1, 2 };
MyCompare myCompare = new MyCompare();//创建自定义比较器实例
list.Sort(myCompare);
foreach(var v in list) {
Console.WriteLine(v);
}
}
}
Queue
Queue (队列) 是常见的数据结构之一,队列是一种先进先出的结构。
Queue 类提供了 4 个构造方法,如下表所示:
构造方法 | 作用 |
---|---|
Queue() | 创建 Queue 的实例,集合的容量是默认初始容量 32 个元素,使用默认的增长因子 |
Queue(ICollection col) | 创建 Queue 的实例,该实例包含从指定实例中复制的元素,并且初始容量与复制的元素个数、增长因子相同 |
Queue(int capacity) | 创建 Queue 的实例,并设置其指定的元素个数,默认增长因子 |
Queue(int capacity, float growFactor) | 创建 Queue 的实例,并设置其指定的元素个数和增长因子 |
增长因子是指当需要扩大容量时,以当前的容量(capacity)值乘以增长因子(growFactor)的值来自动增加容量。
下面使用上表中的构造方法来创建 Queue 的实例,代码如下:
//第 1 中构造器
Queue queueq1 = new Queue();
//第 2 中构造器
Queue queueq2 = new Queue(queue1);
//第 3 中构造器
Queue queueq3 = new Queue(30);
//第 4 中构造器
Queue queueq4 = new Queue(30, 2);
注意:Queue 类不能在创建实例时直接添加值。
Queue类中常用的属性和方法如下表所示:
属性或方法 | 作用 |
---|---|
Count | 属性,获取 Queue 实例中包含的元素个数 |
void Clear() | 清除 Queue 实例中的元素 |
bool Contains(object obj) | 判断 Queue 实例中是否含有 obj 元素 |
void CopyTo(Array array, int index) | 将 array 数组从指定索引处的元素开始复制到 Queue 实例中 |
object Dequeue() | 移除并返回位于 Queue 实例开始处的对象 |
void Enqueue(object obj) | 将对象添加到 Queue 实例的结尾处 |
object Peek() | 返回位于 Queue 实例开始处的对象但不将其移除 |
object[] ToArray() | 将 Queue 实例中的元素复制到新数组 |
void TrimToSize() | 将容量设置为 Queue 实例中元素的实际数目 |
IEnumerator GetEnumerator() | 返回循环访问 Queue 实例的枚举数 |
下面通过实例来演示 Queue 类的使用:
1)创建 Queue 类的实例,模拟排队购电影票的操作。
class Program {
static void Main(string[] args) {
Queue queue = new Queue();
queue.Enqueue("小张");
queue.Enqueue("小李");
queue.Enqueue("小刘");
Console.WriteLine("购票开始");
// 当队列中没有人时,购票结束
while (queue.Count != 0) {
Console.WriteLine(queue.Dequeue() + "已购票。");
}
Console.WriteLine("购票结束...");
}
}
2)向 Queue 类的实例中添加 3 个值,在不移除队列中元素的前提下将队列中的元素依次输出。
class Program {
static void Main(string[] args) {
Queue queue = new Queue();
queue.Enqueue("aaa");
queue.Enqueue("bbb");
queue.Enqueue("ccc");
object[] obj = queue.ToArray();
foreach(var v in obj) {
Console.WriteLine(v);
}
}
}
除了使用 ToArray() 方法以外,还可以使用 GetEnumerator() 方法来遍历,实现的代码如下:
class Program {
static void Main(string[] args) {
Queue queue = new Queue();
queue.Enqueue("aaa");
queue.Enqueue("bbb");
queue.Enqueue("ccc");
IEnumerator enumerator = queue.GetEnumerator();
while (enumerator.MoveNext()) {
Console.WriteLine(enumerator.Current);
}
}
}
Stack
Stack (栈)是常见的数据结构之一,栈是一种先进后出的结构,即元素从栈的尾部插入,从栈的尾部移除。
Stack 类提供了 3 种构造方法,如下表所示。
构造方法 | 作用 |
---|---|
Stack() | 使用初始容量创建 Stack 的对象 |
Stack(ICollection col) | 创建 Stack 的实例,该实例包含从指定实例中复制的元素,并且初始容量与复制的元素个数、增长因子相同 |
Stack(int capacity) | 创建 Stack 的实例,并设置其初始容量 |
Stack 类中的常用属性和方法如下表所示
属性或方法 | 作用 |
---|---|
Push(object obj) | 向栈中添加元素,也称入栈 |
object Peek() | 用于获取栈顶元素的值,但不移除栈顶元素的值 |
object Pop() | 用于移除栈顶元素的值,并移除栈顶元素 |
Clear() | 从 Stack 中移除所有的元素 |
Contains(object obj) | 判断某个元素是否在 Stack 中 |
object[] ToArray() | 复制 Stack 到一个新的数组中 |
下面通过实例来演示 Stack 类的使用。
1) 创建一个栈(Stack),模拟餐馆盘子的存取。
class Program {
static void Main(string[] args) {
Stack stack = new Stack();
//向栈中存放元素
stack.Push("1 号盘子");
stack.Push("2 号盘子");
stack.Push("3 号盘子");
stack.Push("4 号盘子");
stack.Push("5 号盘子");
Console.WriteLine("取出盘子:");
//判断栈中是否有元素
while(stack.Count != 0) {
//取出栈中的元素
Console.WriteLine(stack.Pop());
}
}
}
执行结果如下:
取出盘子:
5 号盘子
4 号盘子
3 号盘子
2 号盘子
1 号盘子
从上面的执行效果可以看出,通过 Stack 类提供的 Pop 方法可以依次从栈顶取出栈中的每一个元素。
Hashtable
Hashtable 类实现了 IDictionary 接口,集合中的值都是以键值对的形式存取的。
C# 中的 Hashtable 称为哈希表,也称为散列表,在该集合中使用键值对(key/value)的形式存放值。
Hashtable 类提供的构造方法有很多,最常用的是不含参数的构造方法:
Hashtable hashtable = new Hashtable ();
Hashtable 类中常用的属性和方法如下表所示:
属性或方法 | 作用 |
---|---|
Count | 集合中存放的元素的实际个数 |
void Add(object key,object value) | 向集合中添加元素 |
void Remove(object key) | 根据指定的 key 值移除对应的集合元素 |
void Clear() | 清空集合 |
ContainsKey (object key) | 判断集合中是否包含指定 key 值的元素 |
ContainsValue(object value) | 判断集合中是否包含指定 value 值的元素 |
1)使用 Hashtable 集合实现图书信息的添加、查找以及遍历的操作
class Program {
static void Main(string[] args) {
Hashtable hashtable = new Hashtable();
hashtable.Add(1, "计算机基础");
hashtable.Add(2, "C#高级编程");
hashtable.Add(3, "数据库应用");
Console.WriteLine("请输入图书编号");
int id = int.Parse(Console.ReadLine());
bool flag = hashtable.ContainsKey(id);
if (flag) {
Console.WriteLine("您查找的图书名称为:{0}", hashtable[id].ToString());
} else {
Console.WriteLine("您查找的图书编号不存在!");
}
Console.WriteLine("所有图书信息如下:");
foreach (DictionaryEntry dictionaryEntry in hashtable) {
int key = (int)dictionaryEntry.Key;
string value = dictionaryEntry.Value.ToString();
Console.WriteLine("图书编号:{0},图书名称:{1}", key, value);
}
}
}
SortedList
SortedList 类实现了 IDictionary 接口 ,集合中的值都是以键值对的形式存取的。
C# SortedList 称为有序列表,按照 key 值对集合中的元素排序。
使用 SortedList 实现挂号信息的添加、查找以及遍历操作。
class Program {
static void Main(string[] args) {
SortedList sortedList = new SortedList();
sortedList.Add(1, "小张");
sortedList.Add(2, "小李");
sortedList.Add(3, "小刘");
Console.WriteLine("请输入挂号编号:");
int id = int.Parse(Console.ReadLine());
bool flag = sortedList.ContainsKey(id);
if (flag) {
string name = sortedList[id].ToString();
Console.WriteLine("查找的患者姓名为:{0}", name);
} else {
Console.WriteLine("查找的挂号编号不存在!");
}
Console.WriteLine("所有的挂号信息如下:");
foreach (DictionaryEntry dictionaryEntry in sortedList) {
int key = (int) dictionaryEntry.Key;
string value = dictionaryEntry.Value.ToString();
Console.WriteLine("挂号编号:{0}, 姓名:{1}", id, value);
}
}
}
泛型
泛型是 C#2.0 推出的新语法,不是语法糖,而是 2.0 由框架升级提供的功能。
泛型是在 System.Collections.Generic 命名空间中的,用于约束类或方法中的参数类型。
泛型的应用非常广泛,包括方法、类以及集合等。
在 ArrayList 中以 double 类型存入学生考试成绩,但存入值时并没有做验证,存入了其他数据类型的值,代码如下。
ArrayList arrayList=new ArrayList();
arrayList.Add(100);
arrayList.Add("abc");
arrayList.Add(85.5);
在输出集合中的元素时,如果使用 double 类型来遍历集合中的元素,代码如下。
foreach (int d in arrayList){
Console.WriteLine(d);
}
执行上面的代码,由于在集合中存放的并不全是 double 类型的值,因此会出现 System.InvalidCastException
异常,即指定的转换无效。
为了避免类似的情况产生,将集合中元素的类型都指定为 double 类型,不能在集合中输入其他类型的值,这种设置方式即为泛型的一种应用。
Nullable
在 C# 语言中提供了一种泛型类型(即可空类型 (System.Nullable
System.Nullable<T> 变量名;
例如定义一个int类型的变量:
Nullable<int> a;
除了使用上面的方法定义可空类型变量以外,还可以通过如下语句定义一个 int 类型的可空类型变量。
int? a
从上面的定义可以看出,int?
等同于Nullable<int>
。
此外,在使用可空类型时也可以通过 HasValue
属性判断变量值是否为 Null 值。
创建一个 int 的可空类型变量和 double 的可空类型变量,并使用 HasValue 属性判断其值是否为空。
class Program {
static void Main(string[] args) {
int? i = null;
double? d = 3.14;
if (i.HasValue) {
Console.WriteLine("i 的值为{0}", i);
}else {
Console.WriteLine("i 的值为空!");
}
if (d.HasValue) {
Console.WriteLine("d 的值为{0}", d);
} else {
Console.WriteLine("d 的值为空!");
}
}
}
泛型方法
在 C# 语言中泛型方法是指通过泛型来约束方法中的参数类型,也可以理解为对数据类型设置了参数。
定义泛型方法需要在方法名和参数列表之间加上<>,并在其中使用 T 来代表参数类型。
class Program {
static void Main(string[] args) {
add<double>(3.3, 4);
add<int>(3, 4);
}
private static void add<T>(T a, T b) {
double sum = double.Parse(a.ToString()) + double.Parse(b.ToString());
Console.WriteLine(sum);
}
}
从上面的执行效果可以看出,在调用 Add 方法时能指定不同的参数类型执行加法运算。
泛型类
C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上
class 类名<T1,T2,…> {
//类的成员
}
这样,在类的成员中即可使用 T1、T2 等类型来定义。
定义泛型类,并在泛型类中定义数组,提供添加和显示数组中全部元素的 方法。
public class MyTest<T> {
private T[] items = new T[3];
private int index = 0;
public void add(T t) {
if (index < 3) {
items[index] = t;
index++;
} else {
Console.WriteLine("数组已满!");
}
}
public void show() {
foreach (T t in items) {
Console.WriteLine(t);
}
}
}
在 Main 方法中调用 MyTest 类中的方法,代码如下:
class Program {
static void Main(string[] args) {
MyTest<int> test = new MyTest<int>();
test.add(10);
test.add(20);
test.add(30);
test.show();
}
}
根据泛型类中指定的数据类型创建数组,并实现了对数组元素的添加和显示。
泛型集合
C# 语言中泛型集合是泛型中最常见的应用,主要用于约束集合中存放的元素。
非泛型集合中的 ArrayList、Hashtable 在泛型集合中分别使用 List
下面以 List
1)使用泛型集合 List
class Program {
static void Main(string[] args) {
List<Student> list = new List<Student>();
list.Add(new Student(1, "小明", 28));
list.Add(new Student(2, "小李", 21));
list.Add(new Student(3, "小赵", 26));
foreach (Student student in list) {
Console.WriteLine(student);
}
}
}
class Student {
private int id;
private string name;
private int age;
public Student(int id, string name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int Id {
get => id;
set => id = value;
}
public string Name {
get => name;
set => name = value;
}
public int Age {
get => age;
set => age = value;
}
public override string ToString() {
return id + ":" + name + ":" + age;
}
}
2)使用泛型集合 Dictionary<K,V> 实现学生信息的添加,并能够按照学号查询学生信息。
class Program {
static void Main(string[] args) {
Dictionary<int, Student> dictionary = new Dictionary<int, Student>();
List<Student> list = new List<Student>();
list.Add(new Student(1, "小明", 28));
list.Add(new Student(2, "小李", 21));
list.Add(new Student(3, "小赵", 26));
dictionary.Add(stu1.id, stu1);
dictionary.Add(stu2.id, stu2);
dictionary.Add(stu3.id, stu3);
Console.WriteLine("请输入学号:");
int id = int.Parse(Console.ReadLine());
if (dictionary.ContainsKey(id)) {
Console.WriteLine("学生信息为:{0}", dictionary[id]);
} else {
Console.WriteLine("您查找的学号不存在!");
}
}
}
IComparable & IComparer
在 C# 语言中提供了 IComparer 和 IComparable 接口比较集合中的对象值,主要用于对集合中的元素排序。
IComparer 接口用于在一个单独的类中实现,用于比较任意两个对象。
IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。
在比较器中还提供了泛型接口的表示形式,即 IComparer
IComparer
对于 IComparer
方法 | 作用 |
---|---|
CompareTo(T obj) | 比较两个对象值 |
如果需要对集合中的元素排序,通常使用 CompareTo 方法实现,下面通过实例来演示 CompareTo 方法的使用。
使用 CompareTo 方法实现比较简单。在 Student 类中添加 CompareTo 方法,代码如下:
class Program {
static void Main(string[] args) {
List<Student> list = new List<Student>();
list.Add(new Student(1, "小明", 28));
list.Add(new Student(2, "小李", 21));
list.Add(new Student(3, "小赵", 26));
foreach (Student student in list) {
Console.WriteLine(student);
}
}
}
class Student :IComparable<Student>{
private int id;
private string name;
private int age;
public Student(int id, string name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int Id {
get => id;
set => id = value;
}
public string Name {
get => name;
set => name = value;
}
public int Age {
get => age;
set => age = value;
}
public int CompareTo(Student? other) {
if (this.age > other.age) {
return 1;
}
return -1;
}
public override string ToString() {
return id + ":" + name + ":" + age;
}
}
运行上面的程序,输出的结果会按照年龄进行排序:
1:小明:20
2:小李:25
3:小赵:26
**IComparable **
上面的示例也可以使用 IComparer
方法 | 作用 |
---|---|
Compare(T obj1,T obj2) | 比较两个对象值 |
下面通过实例演示 IComparer
1)先定义一个比较器的类,再实现对集合中元素的排序
class MyCompare : IComparer<Student> {
public int Compare(Student? x, Student? y) {
if (x.Age > y.Age) {
return 1;
}
return -1;
}
}
2)在 Main 方法中应用该比较器对集合中的元素排序,代码如下:
class Program {
static void Main(string[] args) {
List<Student> list = new List<Student>();
list.Add(new Student(1, "小明", 28));
list.Add(new Student(2, "小李", 21));
list.Add(new Student(3, "小赵", 26));
list.Sort(new MyCompare());
foreach (Student student in list) {
Console.WriteLine(student);
}
}
}
论使用 IComparer