
- 类 别
- 程序设计语言
- 影响语言
- C++、C#、D、Java、JavaScript、ObjectPHP等
- 创始时间
- 1972年
- 主要编译器
- Visual C++、Clang、GCC、Turbo C等
- 中文名
- C语言
- 创始人
- Dennis MacAlistair Ritchie
- 发 源
- BCPL语言
- 外文名
- C Programming Language
-
2020-08-17 14:12:11
泛型是在 System.Collections.Generic 命名空间中的,用于约束类或方法中的参数类型。
泛型的应用非常广泛,包括方法、类以及集合等。
C#泛型简介
在前面《C#集合》一节中介绍了集合,集合中的项允许是 object 型的值,因此可以存放任意类型的值。
例如,在 ArrayList 中以 double 类型存入学生考试成绩,但存入值时并没有做验证,存入了其他数据类型的值,代码如下。ArrayList arrayList=new ArrayList(); arrayList.Add(100); arrayList.Add("abc"); arrayList.Add(85.5); //在输出集合中的元素时,如果使用 double 类型来遍历集合中的元素,代码如下。 foreach (double d in arrayList) { Console.WriteLine(d); }
执行上面的代码,由于在集合中存放的并不全是 double 类型的值,因此会出现 System.InvalidCastException 异常,即指定的转换无效。
为了避免类似的情况产生,将集合中元素的类型都指定为 double 类型,不能在集合中输入其他类型的值,这种设置方式即为泛型的一种应用。
C#可空类型:Nullable
对于引用类型的变量来说,如果未对其赋值,在默认情况下是 Null 值,对于值类型的变量,如果未赋值,整型变量的默认值为 0。
但通过 0 判断该变量是否赋值了是不太准确的。
在 C# 语言中提供了一种泛型类型(即可空类型 (System.Nullable))来解决值类型的变量在未赋值的情况下允许为 Null 的情况。
定义可空类型变量的语法形式如下。
System.Nullable<T> 变量名;
其中,Nullable所在的命名空间 System 在 C# 类文件中默认是直接引入的,因此可以省略 System,直接使用 Nullable 即可;T 代表任意类型,例如定义一个存放 int 类型值的变量,代码如下。
Nullable<int> a;
这样,可以将变量 a 的值设置为 Null。即:
Nullable<int> a = Null;
除了使用上面的方法定义可空类型变量以外,还可以通过如下语句定义一个 int 类型的可空类型变量。
int? a
从上面的定义可以看出,int? 等同于Nullable。
此外,在使用可空类型时也可以通过 HasValue 属性判断变量值是否为 Null 值。
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 的值为空!"); } } } //可空类型允许将值类型变量的值设置为 Null,并可以通过 HasValue 属性判断其是否为 Null 值。
C#泛型方法的定义及使用
在 C# 语言中泛型方法是指通过泛型来约束方法中的参数类型,也可以理解为对数据类型设置了参数。
如果没有泛型,每次方法中的参数类型都是固定的,不能随意更改。
在使用泛型后,方法中的数据类型则有指定的泛型来约束,即可以根据提供的泛型来传递不同类型的参数。
【实例】创建泛型方法,实现对两个数的求和运算。
class Program { static void Main(string[] args) { //将T设置为double类型 Add<double>(3.3, 4); //将T设置为int类型 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); } }
C#泛型类的定义及使用
C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上,当然,也可以定义多个类型,即“<T1,T2,・・・>”。
具体的定义形式如下。
class 类名<T1,T2,…> { //类的成员 }
这样,在类的成员中即可使用 T1、T2 等类型来定义。
【实例】定义泛型类,并在泛型类中定义数组,提供添加和显示数组中全部元素的 方法。
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#泛型集合定义及使用
C# 语言中泛型集合是泛型中最常见的应用,主要用于约束集合中存放的元素。
由于在集合中能存放任意类型的值,在取值时经常会遇到数据类型转换异常的情况,因此推荐在定义集合时使用泛型集合。
前面《C# ArrayList》与《C# Hashtable》中已经介绍了非泛型集合中的 ArrayList、Hashtable。
非泛型集合中的 ArrayList、Hashtable 在泛型集合中分别使用 List 和 Dictionary<K,V> 来表示,其他泛型集合均与非泛型集合一致。
【实例 1】使用泛型集合 List 实现对学生信息的添加和遍历。
//将学生信息定义为一个类,并在该类中定义学号、姓名、年龄属性。 //在泛型集合 List<T> 中添加学生信息类的对象,并遍历该集合。 class Program { static void Main(string[] args) { //定义泛型集合 List<Student> list = new List<Student>(); //向集合中存入3名学员 list.Add(new Student(1, "小明", 20)); list.Add(new Student(2, "小李", 21)); list.Add(new Student(3, "小赵", 22)); //遍历集合中的元素 foreach(Student stu in list) { Console.WriteLine(stu); } } } class Student { //提供有参构造方法,为属性赋值 public Student(int id,string name,int age) { this.id = id; this.name = name; this.age = age; } //学号 public int id { get; set; } //姓名 public string name { get; set; } //年龄 public int age { get; set; } //重写ToString 方法 public override string ToString() { return id + ":" + name + ":" + age; } } //在该泛型集合中存放的是 Student 类的对象,当从集合中取岀元素时并不需要将集合中元素的类型转换为 Student 类的类型,而是直接遍历集合中的元素即可,这也是泛型集合的一个特点。
【实例 2】使用泛型集合 Dictionary<K,V> 实现学生信息的添加,并能够按照学号查询学生信息。
//将在实例 1 中所创建学生信息类的对象作为 Dictionary<K,V> 集合中的 value 值部分,key 值部分使用学生信息类中的学号,这样能很容易地通过学号查询学生的信息。实现的代码如下。 class Program { static void Main(string[] args) { Dictionary<int, Student> dictionary = new Dictionary<int, Student>(); Student stu1 = new Student(1, "小明", 20); Student stu2 = new Student(2, "小李", 21); Student stu3 = new Student(3, "小赵", 22); 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("您查找的学号不存在!"); } } }
根据输入的学号直接从 Dictionary<int,Student> 泛型集合中查询出所对应的学生信息,并且在输出学生信息时不需要进行类型转换,直接输出其对应的 Student 类的对象值即可。
C# IComparable、IComparer接口:比较两个对象的值
在 C# 语言中提供了 IComparer 和 IComparable 接口比较集合中的对象值,主要用于对集合中的元素排序。
IComparer 接口用于在一个单独的类中实现,用于比较任意两个对象。
IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。
在比较器中还提供了泛型接口的表示形式,即 IComparer 和 IComparable 的形式。
对于IComparable 接口,方法如下表所示。
方法 作用 CompareTo(T obj) 比较两个对象值 【实例 1】在上一节《C#泛型集合》中实例 1 的基础上将学生信息按照年龄从大到小输出。
//如果不使用比较器,由于集合中的元素是 Student 类型的,不能直接排序,需要按照 Student 学生信息类中的年龄属性排序,因此代码比较烦琐。 class Student:IComparable<Student> { //提供有参构造方法,为属性赋值 public Student(int id,string name,int age) { this.id = id; this.name = name; this.age = age; } //学号 public int id { get; set; } //姓名 public string name { get; set; } //年龄 public int age { get; set; } //重写ToString 方法 public override string ToString() { return id + ":" + name + ":" + age; } //定义比较方法,按照学生的年龄比较 public int CompareTo(Student other) { if (this.age > other.age) { return -1; } return 1; } } class Program { static void Main(string[] args) { List<Student> list = new List<Student>(); list.Add(new Student(1, "小明", 20)); list.Add(new Student(2, "小李", 21)); list.Add(new Student(3, "小赵", 22)); list.Sort(); foreach(Student stu in list) { Console.WriteLine(stu); } } } //在默认情况下,Sort 方法是将集合中的元素从小到大输出的, 由于在 Student 类中重写了 CompareTo 方法,因此会按照预先定义好的排序规则对学生信息排序。 //需要说明的是,在 CompareTo 方法中返回值大于 0 则表示第一个对象的值大于第二个对象的值,返回值小于 0 则表示第一个对象的值小于第二个对象的值,返回值等于 0 则表示两个对象的值相等。
对于实例 1 中的操作也可以使用 IComparer 接口来实现,IComparer 接口中的方法如下表所示。
方法 作用 Compare(T obj1,T obj2) 比较两个对象值 在使用 IComparer 接口中的 Compare 方法时,需要单独定义一个类来实现该比较方法。
【实例 2】将实例 1 用 IComparer 接口实现。
//先定义一个比较器的类,再实现对集合中元素的排序 class MyCompare : IComparer<Student> { //比较方法 public int Compare(Student x,Student y) { if (x.age > y.age) { return -1; } return 1; } } class Program { static void Main(string[] args) { List<Student> list = new List<Student>(); list.Add(new Student(1, "小明", 20)); list.Add(new Student(2, "小李", 21)); list.Add(new Student(3, "小赵", 22)); //在Sort方法中传递自定义比较器作为参数 list.Sort(new MyCompare); foreach(Student stu in list) { Console.WriteLine(stu); } } }
从上面两个实例可以看出,不论使用 IComparer 接口还是 IComparable 接口都能自定义在集合中使用 Sort 方法时的排序。
提示:不仅在泛型集合中允许使用比较器,在非泛型集合中也允许使用比较器,并且可以使用非泛型接口的比较器。
更多相关内容 -
详解C#泛型的类型参数约束
2020-08-18 17:18:49主要介绍了C#泛型的类型参数约束的相关资料,文中讲解非常细致,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下 -
详解C# 泛型中的数据类型判定与转换
2020-12-17 09:05:33提到类型转换,首先要明确C#中的数据类型,主要分为值类型和引用类型: 1.常用的值类型有:(struct) 整型家族:int,byte,char,short,long等等一系列 浮点家族:float,double,decimal 孤独的枚举:enum 孤独... -
C#泛型实例详解
2020-12-26 03:14:00本文以实例形式讲述了C#泛型的用法,有助于读者深入理解C#泛型的原理,具体分析如下: 首先需要明白什么时候使用泛型: 当针对不同的数据类型,采用相似的逻辑算法,为了避免重复,可以考虑使用泛型。 一、针对类的... -
C# 泛型数组学习小结
2021-01-20 06:50:12C# 泛型和数组在 C# 2.0 中,下限为零的一维数组自动实现 IList。这使您可以创建能够使用相同代码循环访问数组和其他集合类型的泛型方法。此技术主要对读取集合中的数据很有用。IList<T> 接口不能用于在数组中添加或... -
C#泛型类、泛型方法、泛型接口、泛型委托的实例
2018-07-26 15:21:14泛型类、泛型方法、泛型接口、泛型委托 泛型类、泛型方法、泛型接口、泛型委托 -
C# 泛型参数转换
2020-08-31 11:51:41本文介绍了C# 泛型参数转换的相关知识,具有很好的参考价值,下面跟着小编一起来看下吧 -
详细介绍C# 泛型
2021-01-19 23:39:54在C#开发中,必不可少的要用到泛型。泛型是.NET2.0版本就有的,它广泛应用于C#框架中容器的使用中。下面我们来详细介绍一下。 一、泛型的主要优势 1.性能更高。 2.类型更安全。 3.代码更多的重用和扩展性。 ... -
介绍C# 泛型类在使用中约束
2021-01-01 10:06:58访问修饰符 返回类型 泛型方法名 (T 参数)1):无法在泛型方法内部给任何 T 类型创建实例的对象,因为在泛型方法内部不知道传进来的对象有哪些构造函数2):约束是对内部的!(对于泛型方法)约束也是会被继承的!3... -
C#泛型约束的深入理解
2020-12-25 19:09:40where 子句用于指定类型约束,这些约束可以作为泛型声明中定义的类型参数的变量。1.接口约束。例如,可以声明一个泛型类 MyGenericClass,这样,类型参数 T 就可以实现 IComparable<T> 接口: 代码如下:public class... -
C#泛型用法实例分析
2020-12-31 20:28:06本文实例分析了C#泛型用法。分享给大家供大家参考。具体分析如下: 这里演示如何创建具有单个类型参数的自定义泛型列表类,以及如何实现 IEnumerable<T> 以便对列表的内容启用 foreach 迭代。此示例还演示客户端代码... -
深入浅析C#泛型类型
2021-01-01 15:04:17上篇文章给大家介绍了浅析C# 中的类型系统(值类型和引用类型),接下来通过本文给大家介绍下c# 泛型类型, 说下C#中的泛型,熟练地使用泛型能提高代码的重用性,使用我们代码瞬间就高大上了,当然只有一点点,真的... -
C#泛型使用小案例 c#经典案例.pdf
2022-05-07 21:06:21C#泛型使用小案例 c#经典案例.pdf -
C#泛型实例Demo
2019-07-07 14:24:24C#泛型详解文档附实战实例代码,适合C#进阶人群,代码100%能正常运行,有问题可留言! -
C#泛型概念的简介与泛型的使用
2020-08-26 21:36:30今天小编就为大家分享一篇关于C#泛型概念的简介与泛型的使用,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 -
C#泛型内部工作机制详细解析
2020-12-22 22:43:52泛型拥有类型参数,通过类型参数可以提供”参数化”的类型,事实上,泛型类型的”类型参数”变成了泛型类型的元数据,”运行时”在需要的时候会利用他们构造恰当的类型,通过这些类型,我们有可以实例化不同类型... -
c#泛型类、泛型方法、泛型接口、泛型委托
2021-01-08 16:58:57c#泛型类、泛型方法、泛型接口、泛型委托 -
C#泛型相关讲解
2020-09-05 08:20:52我们在编写程序时,经常 遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型 -
浅谈C#泛型的用处与特点
2021-01-01 02:38:58泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个新功能。泛型将类型参数的概念引入 .NET Framework,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例... -
C#泛型与非泛型性能比较的实例
2020-09-08 07:55:26C#泛型与非泛型性能比较的实例,需要的朋友可以参考一下 -
C#泛型Dictionary的用法实例详解
2020-09-04 04:55:18主要介绍了C#泛型Dictionary的用法,并以实例的形式讲述了对键值对的填充、移除及遍历等操作,需要的朋友可以参考下 -
浅谈c# 泛型类的应用
2021-01-01 06:02:25泛型类泛型类封装不是特定于具体数据类型的操作。 泛型类最常用于集合,如链接列表、哈希表、堆栈、队列、树等。 像从集合中添加和移除项这样的操作都以大体上相同的方式执行,与所存储数据的类型无关。对大多集合类... -
C#泛型设计需要注意的一个小陷阱
2020-08-26 06:42:12主要给大家介绍了关于C#泛型设计需要注意的一个小陷阱,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧 -
C# 泛型类(函数)的实例化小例子
2020-09-05 11:15:52C# 泛型类(函数)的实例化小例子,需要的朋友可以参考一下 -
C#泛型委托的用法实例分析
2020-09-03 17:41:10主要介绍了C#泛型委托的用法,以实例形式较为详细的分析了C#委托的功能与相关使用技巧,需要的朋友可以参考下 -
C# 泛型接口的抗变和协变
2020-12-31 18:38:501, 泛型接口的协变 如果泛型类型用out关键字标注,泛型接口就是协变的。这也意味着返回类型只能是T。 泛型接口的抗变 如果泛型类型用in关键字标注,泛型接口就是抗变的。这样,接口只能把泛型类型T用作其方法的输入...