泛型接口例子:一个学生有一个独一无二的ID,但是每个学生的姓名不一定是唯一的。
class Program
{
static void Main(string[] args)
{
Student<ulong> stu = new Student<ulong>();
stu.ID = 2014031026;
stu.Name = "Maomao";
}
}
interface IUnique<Tid>
{
Tid ID { get; set; }
}
class Student<Tid>:IUnique<Tid>
{
public Tid ID { get; set; }
public string Name { get; set; }
}
如果这个类实现的是泛型接口,那么这个类也是泛型的,实现接口的时候必须把接口里全部的成员实现。
另一种情况,类实现的是特化之后的泛型接口,这样的类就不是泛型类了。
class Program
{
static void Main(string[] args)
{
Student stu = new Student();
stu.ID = 2014031026;
stu.Name = "Maomao";
}
}
interface IUnique<Tid>
{
Tid ID { get; set; }
}
class Student : IUnique<ulong>
{
public ulong ID { get; set; }
public string Name { get; set; }
}
直接在类继承接口的时候就注入ulong类型,则类就不需要设置为泛型类了。
泛型List
在我们的.net种,几乎所有常用的数据结构都是泛型的,编程处理的数据中,大量的数据是存储在各种各样集合中的。
常用的集合有数组,列表,链表,字典等,这些数据结构以及它们的基接口,基类都是泛型的。
这些泛型的集合,数据结构以及它们的基接口,基类都集中在名称空间
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
IList<int> list = new List<int>();
for (int i = 0; i < 100; i++)
{
list.Add(i);
}
foreach (var item in list)
Console.WriteLine(item);
}
}
以上是一个带有一个类型参数的IList泛型接口和带有一个类型参数的List泛型类
C#中的List相当于Java中的ArrayList,在List泛型类的背后,维护着一个数组,我们可以不停的往这个数组里放东西,
当我们放的东西太多了超过我们数组的长度的时候 ,会再生成一个更长的数组,然后把我们输入的内容copy到这个更长的数组里。
我们知道数组的长度是不能够改变的,而我们List(Java中的ArrayList)的长度是可以改变的,有的书称之为动态数组。
我们去查看一下带有一个类型参数的List泛型类定义,
它有这么多接口:
ICollection接口代表它是一个集合,我们可以向其中添加移除元素,ICollection的定义为:
可以看到其中的各种方法内也有该类型参数。
不止一个参数类型的泛型接口和泛型类:
并不是所有泛型类都是只有一个参数类型,对于Ditionary这个字典类型(索引对应数据)就有两个参数类型。
TKey是索引,TValue是数据,组成这样的映射关系关系。
我们用int类型作为IDictionary的Key的类型,string类型作为IDictionary的Value类型,
然后IDictionary泛型接口被特化成了以int类型为key,string类型为value 。
我们利用之前学过的多态知识,接口类型的IDictionary变量可以引用一个Dictionary的实例
因为Dictionary泛型类实现了IDictionary接口(上图中所示),而且它的参数类型与IDictionary一致。
代码:
class Program
{
static void Main(string[] args)
{
IDictionary<int, string> dict = new Dictionary<int, string>();
dict[1] = "aaa";
dict[2] = "bbb";
Console.WriteLine($"Student #1 is {dict[1]}");
Console.WriteLine("Student #2 is {dict[2]}");
}
}
输出的第二行我故意不写$,可以看到区别: