定义:泛型允许我们延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。(也就是说泛型是可以与任何数据类型一起工作的类或方法)模块内高内聚,模块间低耦合。
泛型的使用:当我们的类/方法不需要关注调用者传递的实体是什么(公共基类工具类),这个时候就可以使用泛型。
注意:
集合中的项允许是 object 型的值,因此可以存放任意类型的值,无法确保存入集合中的值都是同一类型,而导致在处理时发生异常。
对于引用类型的变量来说,如果未对其赋值,在默认情况下是 Null 值,对于值类型的变量,如果未赋值,整型变量的默认值为 0。
但通过 0 判断该变量是否赋值了是不太准确的。在 C# 语言中提供了一种泛型类型(即可空类型 (System.Nullable
可空类型的定义:
System.Nullable<T> 变量名;
类型? 变量名;
可空类型常用方法:
属性或方法 |
作用 |
HasValue |
若变量有值则为True,若为null则为False |
Value |
返回可空类型变量中存储的真正的值,当HasValue为True时才可以使用 |
举例如下:
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 来代表参数类型。
注意:
C#中泛型方法中只能使用object类具有的方法。
举例如下:
class Program
{
static void Main(string[] args)
{
//将T设置为double类型
GenericFunc<double>(3.3, 4);
//将T设置为int类型
GenericFunc<int>(3, 4);
}
//泛型方法
private static void GenericFunc<T>(T a, T b)
{
Console.WriteLine("参数1:{0} 类型:{1},参数2:{2},类型: {3}",a,a.GetType(),b,b.GetType());
}
}
C# 语言中泛型类的定义与泛型方法类似,是在泛型类的名称后面加上
定义形式如下:
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);28 }
}
}
泛型中的数据约束可以指定泛型类型的范围。
若给T类型的数据约束struct,则T只能接受struct的子类类型,否则编译错误。
C# 语言中泛型集合是泛型中最常见的应用,主要用于约束集合中存放的元素。
由于在集合中能存放任意类型的值,在取值时经常会遇到数据类型转换异常的情况,因此推荐在定义集合时使用泛型集合。
泛型集合中主要使用 List
1、List类
List
2、Dictionary
Dictionary
使用约束:
1、从一组键(Key)到一组值(Value)的映射,每一个添加项都是由一个值及其相关连的键组成
2、任何键都必须是唯一的
3、键不能为空引用null,若值为引用类型,则可以为空值
4、Key和Value可以是任何类型(string,int,class 等)
在 C# 语言中提供了 IComparer 和 IComparable 接口比较集合中的对象值,主要用于对集合中的元素排序。
IComparer 接口用于在一个单独的类中实现,用于比较任意两个对象。
IComparable 接口用于在要比较的对象的类中实现,可以比较任意两个对象。
在比较器中还提供了泛型接口的表示形式,即 IComparer
1、 IComparable 接口
要比较的自定义类型需要继承IComparable
方法 |
作用 |
CompareTo(T obj) |
比较两个对象值,返回值小于0代表当前实例小于比较实例,返回值等于0代表二者相等。返回值大于0代表当前实例大于比较实例 |
如果需要对集合中的元素排序,通常使用 CompareTo 方法实现,下面通过实例来演示CompareTo 方法的使用。
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;
}
else if(this.age == other.age)
{
return 0;
}
else
{
return 1;
}
}
}
2、 IComparer 接口
如果要使得自定义类型可以使用泛型集合中的Sort方法进行排序,那么可自定义一个排序类,实现IComparer
方法 |
作用 |
Compare(T obj1,T obj2) |
比较两个对象值,返回值小于0代表当前实例小于比较实例,返回值等于0代表二者相等。返回值大于0代表当前实例大于比较实例 |
新建学生类型排序类StudentComparer ,实现IComparer
代码如下:
///
/// 比较类,用于两个Student对象比较
///
class StudentComparer : IComparer<Student>
{
///
/// 比较方法
///
///
///
///
public int Compare(Student x, Student y)
{
if(x.age < y.age)
{
return 1;
}
else if(x.age > y.age)
{
return ‐1;
}
else
{
return 0;
}
}
}
class Program
{
static void Main(string[] args)
{
//创建一个泛型列表,列表中的元素类型为Student
List<Student> stuList = new List<Student>();
//在元素中添加三个元素
stuList.Add(new Student(3, "张三", 20));
stuList.Add(new Student(1, "李四", 15));
stuList.Add(new Student(2, "王五", 18));
//遍历并输出
foreach (var stu in stuList)
{
Console.WriteLine(stu);
}
Console.WriteLine("排序后:");
//排序
stuList.Sort(new StudentComparer());
//遍历并输出
foreach(var stu in stuList)
{
Console.WriteLine(stu);
}
}
}