泛型约束
使用泛型时会假设泛型占位符是任何类型。
但因为它被假设是任何类型,所以使用起来有很大的限制。只有所有类型都有的功能,他才能用。
为了满足所有的可能类型,可用的操作非常少。
为此我们可以为泛型占位符添加约束。虽然会让能兼容的类型变少,但是可以使用更多的操作。
声明约束
在函数的参数列表后,或泛型类的泛型占位符后使用where关键字+冒号指定约束。
一个占位符的多个约束间使用逗号隔开。为多个占位符指定约束需要使用多个where,没有分隔符。
class Foo<T> where T : class
{
public void Boo<E, F>() where E : class, new() where F : class
{
}
}
可用约束
派生自类
如果要求泛型占位符代表的类型派生自某一类型,
只需要直接写类型名。如果只要求是一个类,那么使用class。
显然,类型约束不能是密封类或静态类。类型名可以是一个泛型占位符
具有类型约束后,可调用此类型有权限访问的实例方法。
是结构
是一种结构,使用struct。
不能是可为空的结构使用notnull。
必须是非托管类型使用unmanaged。
非托管类型是指不包含任何引用类型字段的结构(且他的字段的字段,一直递归下去,都不包含)。
托管类型即指引用类型,这些类型会放在堆内存里,并由运行时管理。
实现接口
实现接口只需要直接写接口名。
但是正如继承时的语法一样,接口约束必须写在类约束或结构约束之后。
默认占位符以隐式实现方式实现接口所有方法。
也就是说可以直接从参数中调用接口的方法。
在多个接口存在同名方法时需要转化为接口再调用。
如果接口存在静态抽象方法,则可以通过类型占位符访问静态方法。
void Boo<T>(T t) where T : IInterface
{
T.aa();
}
interface IInterface
{
public static abstract void aa();
}
其他
new()约束:虽然看起来只是说要有一个无参构造器。但实际上还要求这个构造器是公开的。
也就是要求目标类型具有公共无参构造器。具有此约束的类型可以在函数中调用这个构造器。
new约束必须放在约束列表的最后一个。
default约束:这个约束名字没起好,改为base约束更容易理解。他的实际作用是在重写或显式实现接口时
表示基方法或基类的约束,但class和struct约束除外。
互斥的约束
不能同时存在的约束,要么是因为不兼容,要么是因为有包含关系。
不能兼容的约束:类约束和结构约束。
有包含的约束:unmanaged约束一定是一种struct约束,struct约束一定是一种new()约束。