C#中的泛型
一、泛型的概念
定义:泛型允许我们延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程
序中使用它的时候。(也就是说泛型是可以与任何数据类型一起工作的类或方法)模块内高
内聚,模块间低耦合。
泛型的使用:当我们的类/方法不需要关注调用者传递的实体是什么(公共基类工具
类),这个时候就可以使用泛型。
注意:
集合中的项允许是 object 型的值,因此可以存放任意类型的值,无法确保存入集合中
的值都是同一类型,而导致在处理时发生异常。
泛型的特性:
-有助于最大限度地重用代码、保护类型的安全以及提高性能。
-可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
-可创建泛型集合类
-可对泛型进行约束以访问特定数据类型的方法
-关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取
二、可空类型
对于引用类型的变量来说,如果未对其赋值,在默认情况下是 Null 值,对于值类型的
变量,如果未赋值,整型变量的默认值为 0。
但通过 0 判断该变量是否赋值了是不太准确的。在 C# 语言中提供了一种泛型类型
(即可空类型 (System.Nullable<T>))来解决值类型的变量在未赋值的情况下允许为 Null的情况。
可空类型的定义:
1 System.Nullable<T> 变量名;
2 类型? 变量名;
可空类型常用方法:
属性或方法
作用
HasValue
若变量有值则为True,若为null则为False
Value
返回可空类型变量中存储的真正的值,当HasValue为True时才可以使用
举例如下:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 int? i = null;
6 double? d = 3.14;
7 if (i.HasValue)
8 {
9 Console.WriteLine("i 的值为{0}", i);
10 }
11 else
12 {
13 Console.WriteLine("i 的值为空!");
14 }
15 if (d.HasValue)
16 {
17 Console.WriteLine("d 的值为{0}", d);
18 }
19 else
20 {
21 Console.WriteLine("d 的值为空!");
22 }
23 }24 }
三、泛型方法
在 C# 语言中泛型方法是指通过泛型来约束方法中的参数类型,也可以理解为对数据类型设
置了参数。
如果没有泛型,每次方法中的参数类型都是固定的,不能随意更改。
在使用泛型后,方法中的数据类型则有指定的泛型来约束,即可以根据提供的泛型来传递不
同类型的参数。
泛型方法的定义:
定义泛型方法需要在方法名和参数列表之间加上<>,并在其中使用 T 来代表参数类型。
注意:
C#中泛型方法中只能使用object类具有的方法。
举例如下:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //将T设置为double类型
6 GenericFunc<double>(3.3, 4);
7 //将T设置为int类型
8 GenericFunc<int>(3, 4);
9 }
10
11 //泛型方法
12 private static void GenericFunc<T>(T a, T b)
13 {
14 Console.WriteLine("参数1:{0} 类型:{1},参数2:{2},类型:
{3}",a,a.GetType(),b,b.GetType());
15 }
16 }
- 泛型类
C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上<T>,当然,也可以定
义多个类型,即“<T1,T2,・・・>”。
定义形式如下:
1 class 类名<T1,T2,…>
2 {
3 //类的成员
4 }
这样,在类的成员中即可使用 T1、T2 等类型来定义。
举例如下:
1 /// <summary>
2 /// 自定义泛型类
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 class MyTest<T>
6 {
7 private T[] items = new T[3];
8 private int index = 0;
9 //向数组中添加项
10 public void Add(T t)
11 {
12 if (index < 3)
13 {
14 items[index] = t;
15 index++;
16 }
17 else
18 {
19 Console.WriteLine("数组已满!");
20 }
21 }
22 //读取数组中的全部项
23 public void Show()
24 {
25 foreach(T t in items)
26 {
27 Console.WriteLine(t);28 }
29 }
30 }
五、泛型中的数据约束
泛型中的数据约束可以指定泛型类型的范围。
若给T类型的数据约束struct,则T只能接受struct的子类类型,否则编译错误。
举例如下:
1 /// <summary>
2 /// 限定了类型的范围:只能是IShape接口的实现类
3 /// </summary>
4 /// <typeparam name="T"></typeparam>
5 class MyTest<T> where T:IShape
6 {
7 private T[] items = new T[3];
8 private int index = 0;
9 //向数组中添加项
10 public void Add(T t)
11 {
12 if (index < 3)
13 {
14 items[index] = t;
15 index++;
16 }
17 else
18 {
19 Console.WriteLine("数组已满!");
20 }
21 }
22 //读取数组中的全部项
23 public void Show()
24 {
25 foreach (T t in items)
26 {
27 Console.WriteLine(t);
28 }
29 }30 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 MyTest<Rectangle> testObj = new MyTest<Rectangle>();
6
7 testObj.Add(new Rectangle(100,200));
8 testObj.Add(new Rectangle(50, 50));
9
10 testObj.Show();
11 }
12 }
六、泛型集合
C# 语言中泛型集合是泛型中最常见的应用,主要用于约束集合中存放的元素。
由于在集合中能存放任意类型的值,在取值时经常会遇到数据类型转换异常的情况,因此推
荐在定义集合时使用泛型集合。
泛型集合中主要使用 List<T> 和 Dictionary<K,V> 。
1、List<T>类
List<T>类是 ArrayList 类的泛型等效类。该类使用大小可按需动态增加的数组实现
IList<T> 泛型接口。
举例如下:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //定义泛型集合
6 List<int> list = new List<int>();
7 //向集合中存入3个变量
8 list.Add(5);
9 list.Add(10);
10 list.Add(15);11 //遍历集合中的元素
12 foreach (var i in list)
13 {
14 Console.WriteLine(i);
15 }
16 }
17 }
2、Dictionary<K,V>
Dictionary<K,V>是 HashTable相对应的泛型集合,其存储数据的方式与哈希表相似,通
过键/值来保存元素,并具有泛型的全部特征,编译时检查类型约束,读取时无须类型转
换。
使用约束:
从一组键(Key)到一组值(Value)的映射,每一个添加项都是由一
个值及其相关连的键组成
任何键都必须是唯一的
键不能为空引用null,若值为引用类型,则可以为空值
Key和Value可以是任何类型(string,int,class 等)
举例如下:
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Dictionary<int, Student> dictionary = new Dictionary<int, Student>();
6 Student stu1 = new Student(1, "小明", 20);
7 Student stu2 = new Student(2, "小李", 21);
8 Student stu3 = new Student(3, "小赵", 22);
9 dictionary.Add(stu1.id, stu1);
10 dictionary.Add(stu2.id, stu2);
11 dictionary.Add(stu3.id, stu3);
12 Console.WriteLine("请输入学号:");
13 int id = int.Parse(Console.ReadLine());
14 if (dictionary.ContainsKey(id))
15 {
16 Console.WriteLine("学生信息为:{0}", dictionary[id]);17 }
18 else
19 {
20 Console.WriteLine("您查找的学号不存在!");
21 }
22 }
23 }
七、IComparable、IComparer自定义排序
在 C# 语言中提供了 IComparer 和 IComparable 接口比较集合中的对象值,主要用于对
集合中的元素排序。
IComparer 接口用于在一个单独的类中实现,用于比较任意两个对象。
IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。
在比较器中还提供了泛型接口的表示形式,即 IComparer<T> 和 IComparable<T> 的形
式。
1、 IComparable<T> 接口
要比较的自定义类型需要继承IComparable <T> 接口,并实现以下方法:
方法
作用
CompareTo(T obj)
比较两个对象值
返回值小于0代表当前实例小于比较实例
返回值等于0代表二者相等。
返回值大于0代表当前实例大于比较实例
如果需要对集合中的元素排序,通常使用 CompareTo 方法实现,下面通过实例来演示
CompareTo 方法的使用。
1 class Student:IComparable<Student>
2 {
3 //提供有参构造方法,为属性赋值
4 public Student(int id,string name,int age)
5 {
6 this.id = id;
7 this.name = name;
8 this.age = age;
9 }10 //学号
11 public int id { get; set; }
12 //姓名
13 public string name { get; set; }
14 //年龄
15 public int age { get; set; }
16 //重写ToString 方法
17 public override string ToString()
18 {
19 return id + ":" + name + ":" + age;
20 }
21 //定义比较方法,按照学生的年龄比较
22 public int CompareTo(Student other)
23 {
24 if (this.age < other.age)
25 {
26 return ‐1;
27 }
28 else if(this.age == other.age)
29 {
30 return 0;
31 }
32 else
33 {
34 return 1;
35 }
36 }
37 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //创建一个泛型列表,列表中的元素类型为Student
6 List<Student> stuList = new List<Student>();
7 //在元素中添加三个元素
8 stuList.Add(new Student(3, "张三", 20));
9 stuList.Add(new Student(1, "李四", 15));
10 stuList.Add(new Student(2, "王五", 18));
1112 //遍历并输出
13 foreach (var stu in stuList)
14 {
15 Console.WriteLine(stu);
16 }
17
18 Console.WriteLine("排序后:");
19 //排序
20 stuList.Sort();
21
22 //遍历并输出
23 foreach(var stu in stuList)
24 {
25 Console.WriteLine(stu);
26 }
27 }
28 }
2、 IComparer <T> 接口
如果要使得自定义类型可以使用泛型集合中的Sort方法进行排序,那么可自定义一个排序
类,实现IComparer <T> 接口中的以下方法:
方法
作用
Compare(T obj1,T obj2)
比较两个对象值
返回值小于0代表当前实例小于比较实例
返回值等于0代表二者相等。
返回值大于0代表当前实例大于比较实例
新建学生类型排序类StudentComparer ,实现IComparer<Student>接口。
代码如下:
1 /// <summary>
2 /// 比较类,用于两个Student对象比较
3 /// </summary>
4 class StudentComparer : IComparer<Student>
5 {
6 /// <summary>
7 /// 比较方法
8 /// </summary>
9 /// <param name="x"></param>10 /// <param name="y"></param>
11 /// <returns></returns>
12 public int Compare(Student x, Student y)
13 {
14 if(x.age < y.age)
15 {
16 return 1;
17 }
18 else if(x.age > y.age)
19 {
20 return ‐1;
21 }
22 else
23 {
24 return 0;
25 }
26 }
27 }
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 //创建一个泛型列表,列表中的元素类型为Student
6 List<Student> stuList = new List<Student>();
7 //在元素中添加三个元素
8 stuList.Add(new Student(3, "张三", 20));
9 stuList.Add(new Student(1, "李四", 15));
10 stuList.Add(new Student(2, "王五", 18));
11
12 //遍历并输出
13 foreach (var stu in stuList)
14 {
15 Console.WriteLine(stu);
16 }
17
18 Console.WriteLine("排序后:");
19 //排序
20 stuList.Sort(new StudentComparer());
2122 //遍历并输出
23 foreach(var stu in stuList)
24 {
25 Console.WriteLine(stu);
26 }
27 }
28 }