一、泛型约束
默认情况下,泛型的类型参数可以是任何类型的。
为什么要使用类型参数的约束呢?
简单点说就是筛选类型参数,在使用泛型的代码中如果违反了某个约束不允许的类型来实例化则会产生编译错误,类型参数的约束是使用关键字where。 下面列出了6中类型的约束
泛型约束有以下几种:
where T:base-class //表示必须是某个父类的紫烈
where T:interface //表示必须实现某个接口 ,当然一般这样自身就是类
where T:class //表示必须是引用类型
where T:struct //表示必须是值类型,不包括可空类型
where T:new() //表示必须有一个无参数的构造函数
whereU:T //U必须继承于T
举例:
class MyList<T>
{
List<T> list = new List<T>();
public T this[int i]
{
get { return list[i]; }
set { this.list[i] = value; }
}
}
class Person
{
public string Name { get; set; }
}
接下来,依次修改演示代码底稿,来说明不同类型的泛型约束。
1、 指定泛型参数为值类型
class MyList<T> where T:struct
{
…代码省略部分
}
看看加上约束后的效果怎么样,按下面方式 实例化MyList 类 :
MyList<Person> list = new MyList<Person>();
你会发现,将产生如下错误提示:
类型“GencConstraint.Person”必须是不可为 null 的值类型才能用作泛型类型或方法“GencConstraint.MyList<T>”中的参数“T”。
使用下面的方式实例化MyList 类 ,将一切正常:
MyList<int> list = new MyList<int>();
2 、 指定泛型参数为引用类型
class MyList<T> where T:class
{
…代码省略部分
}
修改泛型约束为 引用类型后,前面的错误提示消失,因为 Person 类是引用类型,满足泛型约束。
3 、 指定泛型参数有无参的公共的构造函数
class MyList<T> where T:new()
{
…代码省略部分
}
为Person类增加私有的无参构造函数,代码如下:
class Person
{
public string Name { get; set; }
private Person()
{
//do nothing
}
}
实例化 MyList < Person > 类:
MyList<Person> list = new MyList<Person>();
出现编译错误,提示:
“GencConstraint.Person”必须是具有公共的无参数构造函数的非抽象类型,才能用作泛型类型或方法“GencConstraint.MyList”中的参数“T”。
哈哈,约束起作用了。
4、 指定泛型参数 必须派生于指定基类
增加抽象类 SeniorAnimal
abstract class SeniorAnimal//高级动物
{
public abstract void Speak();//会说话
public abstract void UseTool();//会使用工具
}
指定泛型参数 必须派生于基类 SeniorAnimal
class MyList<T> where T : SeniorAnimal
{
…代码省略部分
}
实例化 MyList < Person > 类(此时Person类还未继承自 SeniorAnimal 类 ):
MyList<Person> list = new MyList<Person>();
出现编译错误,提示:
不能将类型“GencConstraint.Person”用作泛型类型或方法“GencConstraint.MyList<T>”中的类型参数“T”。没有从“'GencConstraint.Person”到“GencConstraint.SeniorAnimal”的隐式引用转换。
修改代码,使Person类继承自 SeniorAnimal 类
class Person : SeniorAnimal
{
public string Name { get; set; }
public override void Speak()
{
Console.WriteLine(“我会说脏话!”);
}
public override void UseTool()
{
Console.WriteLine(“我会用砍刀!”);
}
}
再次编译,一切正常。
5、 指定泛型参数 必须实现指定接口
演示情况和第4点类似,就不提供演示代码了。
6 、 指定泛型参数 必须派生于泛型类型U(裸类型约束)
class MyList<U> where U : SeniorAnimal
{
List<U> list = new List<U>();
public void ShowInfo<T>() where T : U
{
}
}
另外,可以为同一泛型参数应用多个约束。