CS4L6——泛型约束

本章代码关键字

1
where    //泛型约束关键字

泛型约束

让泛型的类型有一定的限制,关键字:where​,泛型约束一共有6种,可以组合使用(部分约束不能组合使用)

  1. 值类型 —— where 泛型字母 : struct
  2. 引用类型 —— where 泛型字母 : class
  3. 存在无参公共构造函数 —— where 泛型字母 : new()
  4. 某个类本身或者派生类 —— where 泛型字母 : 类名
  5. 某个接口的派生类型 —— where 泛型字母 : 接口名
  6. 另一个泛型类型本身或者派生类型 —— where 泛型字母 : 另一个泛型字母

where 泛型字母 : (约束的类型)

各泛型约束讲解

值类型约束

where 泛型字母 : struct​ 限定泛型只能为值类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test1<T> where T : struct
{
public T value;
public void TestFun<K>(K v) where K : struct { }
}

internal class Program
{
static void Main(string[] args)
{
Test1<int> t = new Test1<int>(); //泛型约束可以使得实例化时泛型的类型指定加上限制
t.TestFun(1.2f); //值类型约束 使得 泛型只能是值类型的
}
}

引用类型约束

where 泛型字母 : class​ 限定泛型只能是引用类型的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Test2<T> where T : class
{
public T value;
public void TestFun<K>(K v) where K : class { }
}

internal class Program
{
static void Main(string[] args)
{
//引用类型约束 使得 泛型只能是引用类型的
Test2<Random> t2 = new Test2<Random>();
t2.value = new Random();
t2.TestFun(new object());
}
}

公共无参构造约束

where 泛型字母 : new()​ 使得泛型不能是没有 公共的无参构造函数 的非抽象类型(意味着抽象类是不能用的)
结构体一定有公共无参构造函数,因此值类型是可以用的

如果一个类,接口或者方法的泛型参数使用了公共无参构造约束,那么在内部,这个泛型参数就可以使用 new T()​ 来实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Test3<T> where T : new()
{
public T value = new T(); // 只有当T有公共无参构造约束时,才能使用new来实例化
public void TestFun<K>(K v) where K : new() { }
}

abstract class Test { } //这个类有无参构造函数,但抽象类不能实例化,因此有公共无参构造函数也没有用

class Test1 { } //这个类有无参构造函数

//这个类没有无参构造函数
class Test2
{
public Test2(int a) { }
}

internal class Program
{
static void Main(string[] args)
{
Console.WriteLine("泛型约束");

//泛型约束可以使得实例化时泛型的类型指定加上限制
Test1<int> t = new Test1<int>();

//值类型约束 使得 泛型只能是值类型的
t.TestFun(1.2f);

//引用类型约束 使得 泛型只能是引用类型的
Test2<Random> t2 = new Test2<Random>();
t2.value = new Random();
t2.TestFun(new object());

//公共无参构造约束使得 泛型 不能是 没有 公共的无参构造函数 的 非抽象类型(意味着抽象类是不能用的)
//结构体一定有公共无参构造函数,因此值类型是可以用的
//Test3<Test2> t3 = new Test3<Test2>();
Test3<Test1> t3 = new Test3<Test1>();
Test3<int> t4 = new Test3<int>();
}
}

类约束

where 泛型字母 : 类名​ 使得泛型只能是,某个类及其子类(该类的父类也不行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Test1 { }

class Test4<T> where T : Test1
{
public T value;
public void TestFun<K>(K v) where K : Test1 { }
}
//这是test1的子类
class Test3 : Test1 { }

internal class Program
{
static void Main(string[] args)
{
//类约束使得 泛型 只能是某个类及其子类(该类的父类也不行)
Test4<Test1> t5 = new Test4<Test1>();
Test4<Test3> t6 = new Test4<Test3>();
t5.TestFun<Test4<Test1>>(t5);
}
}

接口约束

where 泛型字母 : 接口名​ 使得泛型只能是某个接口及其派生类型(类和接口)
(注意接口不可以实例化!!!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface IFly { }
class Test4 : IFly { }

class Test5<T> where T : IFly
{
public T value;
public void TestFun<K>(K v) where K : IFly { }
}

internal class Program
{
static void Main(string[] args)
{
//接口约束使得 泛型只能是 某个接口及其派生类型(类和接口)(注意接口不可以实例化!!!)
Test5<IFly> t7 = new Test5<IFly>();
t7.value = new Test4();
Test5<Test4> t8 = new Test5<Test4>();
t8.value = new Test4();
}
}

另一个泛型类型的泛型约束

where 泛型字母 : 另一个泛型字母​ 使得被约束的泛型只能是 约束泛型指定的类型本身及其派生类型
(用于有多个泛型字母的类型,将特定字母的泛型,限定为其他字母指定的类型或是派生类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface IFly { }
class Test4 : IFly { }

class Test6<T, U> where T : U
{
public T value;
public void TestFun<K, V>(K v) where K : V { }
}

internal class Program
{
static void Main(string[] args)
{
//另一个泛型约束使得 被约束的泛型 只能是 约束泛型指定的类型本身及其派生类型(用于有多个泛型字母的类型,将该字母的泛型,限定为其他字母指定的类型)
Test6<Test4, IFly> t9 = new Test6<Test4, IFly>(); //T必须是U或者派生于U的
}
}

约束的组合使用

可以将多个约束类型以逗号分割的形式来组合使用

注意,有些类型不能被组合使用,例如值类型约束和引用类型约束,公共无参构造约束(new()​)一定是写在最后一位!!!

1
class Test7<T> where T : class, new() { }

多个泛型有约束

多个泛型有约束时,分别对他们使用 where​ 关键字,使用约束类型即可
用多个 where​ 连接即可,不需要逗号等多余的符号
建议继承和类的泛型约束分行写!以分清继承和泛型约束

1
2
3
4
class Test8<T, K> : Test4
where T : class, new() where K : struct
{
}