泛型(Generic),是将不确定的类型预先定义下来的一种C#高级语法,我们在使用一个类,接口或者方法前,不知道用户将来传什么类型,或者我们写的类,接口或方法相同的代码可以服务不同的类型,就可以定义为泛型。这会大大简化我们的代码结构,同时让后期维护变得容易。
泛型很适用于集合,我们常见的泛型集合有:List<T>,Dictionary<K,V>等等(T,K,V就代表不确定的类型,它是一种类型占位符),无一不是利用的泛型这一特性,若没有泛型,我们会多出很多重载方法,以解决类型不同,但是执行逻辑相同的情况。
自定义泛型:
学会自定义泛型,那么遇到微软为我们预先定义好的泛型数据结构也会很容易理解。
支持泛型定义的数据结构有类,接口,方法,委托
定义泛型的方法就是在名称后添加<T>,T可以是任何字符,可以定义多个泛型<T1,T2...>,只要符合C#命名规范即可,但我们一般用只T,定义以后,在其代码块中的任何位置即可引用这一类型T,我们在用的时候传入的类型,会替代所有的T,所以不要认为泛型是弱类型,它是强类型的。
下面进行代码演示:
public class MyGeneric<T>{...code...}//泛型类 public T GenericMethod<T>{...code...}//泛型方法 interface IGeneric<T>{...code...}//泛型接口 delegate void DeleGeneric<T1,T2>();//泛型委托
default关键字:
在switch语句中,用到了default关键字,用于匹配case没捕获到的情况,在泛型中,由于T可能是值类型也可能是引用类型,我们编码时无法确定,所以我们无法通过正常形式,将T赋给一个既定的类型,所以有如下语法:
defalut(T);//根据类型被赋值类型,引用类型则返回null,值类型则返回对应的默认值
约束类型:
为了避免用户随意使用泛型,我们可以给泛型加约束,约束关键字是where,我们可以把泛型设置为必须继承某个类,或者必须是引用或者值类型(泛型方法也可以设置约束,但显然有些约束不适合方法,比如继承某个类,这是类特有的性质),请先看如下代码:
class MyGeneric<T> where T:SuperGeneric,new(){...} class MyGeneric<T1,T2> where T1:new() where T2:new(){...} class MyGeneric<T> :IEnumerable where T:SuperGeneric,new(){...}
第一行,指定T,必须继承SuperGeneric类,而且必须有一个公共无参的构造方法
第二行,分别用where 指定了T1,T2的约束,对于多个泛型类型,添加约束就要这样写,一个where对应一个泛型类型
第三行,是个要注意的点,泛型约束要定义在类继承语法的后面,这是必要的,因为放在where后会引起歧义
约束类型有以下几个:
注意,new()必须放在约束的最后
泛型在继承中需要注意的点:
子类继承泛型,子类泛型的约束不能大于父类约束或者与父类约束冲突,比如父类泛型约束是值类型,那么子类的泛型约束就不能设置为引用类型。
如果继承泛型类,那么子类要么也是泛型类,要么显示指定父类泛型的类型,以下代码是错误的:
class ChildClass:Ilist<T>{...}//编译不通过,使用时无法确定T的类型
可以显示设置,或者设置子类为泛型:
class ChildClass:Ilist<string>{...} class ChildClass<T>:Ilist<T>{...}
这是我的公众号,获取最新文章,请关注此号