这篇文章是翻译的微软的技术文章 .供学习c#的朋友参考,请勿用于商业目的。 http://msdn.microsoft.com/vcsharp/team/language/default.aspx
由于这一章非常长可能需要分几篇:)
20 .泛型
20.1 泛型类声明
泛型类声明是一个需要提供类型参数以形成实际类型的类的声明。
类声明可以有选择地定义类型参数。
class-declaration : (类声明)
attributes opt class-modifiers opt class identifier opt type-parameter-list opt class –base opt type-parameter-constraints-clause opt class-body ; opt ( 特性 可选 类修饰符 可选 类标识符 可选 类型参数列表 可选 基类 可选 类型参数约束语句 可选 类体 ; 可选 )
除非提供了类型参数列表,类声明可以不提供类型参数化约束语句。
提供了类型参数列表的类声明是一个泛型类声明。此外,任何嵌入到泛型类声明或泛型结构声明中的类,自身是一个泛型类声明,因为必须提供包含类型的类型参数以创建构造类型( constructed type );
泛型类通过使用构造类型而被引用(§ 20.5)。给定泛型类声明
class List
1<t>{}
2
3这是构造类型的一些例子, List<t> , List<int> 和 List<list<string>> 。构造类型可以使用一个或多个参数,例如 List<t> 被称为开放构造类型( open constructed type ) 。不使用类型参数的构造类型,例如 List<int> 被称为封闭构造类型( closed constructed type ) 。
4
5泛型类型不可以被“重载”;也就是说,和普通类型一样在一个作用域内,泛型类型必须被唯一地命名。
6
7
8
9
10class C{}
11
12class C<v>{}// 错误, C 定义了两次
13
14class C<u,v>{}// 错误, C 定义了两次
15
16然而在非限定类型名字查找(§ 20.9.3)中使用的类型查找规则和成员访问(§20.9.4),确实考虑到了类型参数的个数。
17
18### 20.1.1 类型参数
19
20类型参数可以在一个类声明上提供。每个类型参数是一个简单的标识符,它指示了用来创建一个构造类型的类型参数的占位符。类型参数是在后面将要被提供的类型的形式占位符。相反,类型参数§ 20.5.1 )只是在构造类型被引用时,实际类型的一个替代。
21
22_ type-parameter-list _ :(类型参数列表:)
23
24< _type-parameters_ > ( < 类型参数 > )
25
26_ type-parameters _ :(类型参数:)
27
28_type-parameter_ (类型参数)
29
30_type-parameters type-parameter_ (类型参数,类型参数)
31
32_ type-parameter _ :(类型参数:)
33
34_attributes_ opt _identifier_ (特性 可选 标识符)
35
36在类声明中的每个类型参数在类的声明空间(§ 3.3)定义了一个名字。由此,它不能和另一个类型参数或在类中声明的成员有同样的名字。类型参数不能和类型自身有同样的名字。
37
38在一个类中的类型参数的作用域(§ 3.7),包括基类 、 类型参数约束语句和类体。不像类的成员,它没有扩展到派生类。在其作用域之内,类型参数可以被用作一个类型。
39
40_type_ (类型):
41
42_value-type_ (值类型)
43
44_reference-type_ (引用类型)
45
46_type-parameter_ (类型参数)
47
48由于类型参数可以被许多不同的实际类型实参所实例化,类型参数与其他类型相比将略微有一些不同的操作和限制。包括如下内容。
49
50 * 类型参数不能用于直接声明一个基类型或者接口
51 * 对于在类型参数上的成员查找规则,如果约束存在,则依赖于应用到该类型参数的约束。更详细地说明参看§ 20.7.4 。
52
53
54
55
56
57
58 * 类型参数可行的转换依赖于应用到该类型参数上的约束(如果有的话)。详细地说明参看§ 20.7.4 。
59 * 字面 null 不能被转换到由类型参数所给定的类型,除非类型参数是由一个类约束(§ 20.7.4 )所约束。然而可以使用一个默认值表达式(§ 20.8.1 )代替。此外,由一个类型参数给定的类型的值可以使用“ == ”和“ != ”(§ 20.8.4 )与 null 进行比较。
60 * 如果类型参数通过一个构造函数约束( constructor-constraint )(§ 20.7 )而约束, new 表达式只能用过一个类型参数而被使用。
61 * 类型参数不能用于特性内的任何地方。
62 * 类型参数不能用于成员访问,或者表示一个静态成员或者嵌套类型的类型名字(§ 20.9.1 、§ 20.9.4 )。
63 * 在不安全代码中,类型参数不能被用作托管类型(§ 18.2 )。
64
65
66
67作为一种类型,类型参数纯粹只是一个编译时构件。在运行时,每个类型参数被绑定到运行时类型,它是通过泛型类型声明所提供的类型实参所指定的。为此,在运行时,使用类型参数声明的变量类型是一个封闭类型( closed type )(§ 20.5.2)。所有语句和表达式在运行时执行所使用的类型参数,都是由那个参数作为类型实参而提供的实际类型。
68
69### 20.1.2 实例类型
70
71每个类声明都有与之关联的构造类型,即实例类型 (instance type) 。 对于一个泛型类声明,实例类型通过创建一个来自于类型声明的构造类型(§ 20.4 )而形成,它使用对应于类型参数的每一个类型实参。由于实例化类型使用类型参数,在类型参数作用域内(类声明之内),它是唯一有效的。实例类型在类声明中是 this 的类型。对于非泛型类,实例类型只是一个声明类型。下面展示了几个声明类,以及它们的实例类型。
72
73class A<t> // 实例类型: A<t>
74
75{
76
77class B{} // 实例类型: A<t>.B
78
79class C<u>{} // 实例类型: A<t>.C<u>
80
81}
82
83class D{} // 实例类型: D
84
85### 20.1.3 基类规范
86
87在类声明中指定的基类可以是一个构造类型(§ 20.5 )。一个基类其自身不能是一个类型参数,但在其作用域内可以包含类型参数。
88
89
90
91
92class Extend<v>: V{}// 错误,类型参数被用作基类
93
94泛型类声明不能使用 System.Attribute 作为直接或间接基类。
95
96在一个类声明中指定的基接口可以是构造接口类型(§ 20.5)。基接口自身不能是类型参数,但在其作用域内可以包含类型参数,下面的代码演示了如何实现和扩展构造类型。
97
98class C<u,v>{}
99
100Interface I1<v>{}
101
102class D:C<string ,="" int="">,I1<string>{}
103
104class E<t>:C<int,t> ,I1<t>{}
105
106泛型类型声明的基接口必须满足§ 20.3.1中所描述的唯一性规则。
107
108从基类或接口重写或实现方法的类的方法,必须提供特定类型的合适方法。下面的代码演示了方法如何被重写和实现。这将会在§ 20.1.10中进一步解释。
109
110class C<u,v>
111
112{
113
114public virtual void M1(U x , List<v> y){…}
115
116}
117
118interface I1<v>
119
120{
121
122V M2(V x);
123
124}
125
126class D:C<string ,="" int="">,I1<string>
127
128{
129
130public override void M1(string x , List<int> y){…}
131
132public string M2(string x){…}
133
134}
135
136### 20.1.4 泛型类的成员
137
138泛型类的所有成员都可以直接地或者作为构造类型的一部分,从任何封闭类( enclosing class )中使用类型参数。当特定的封闭构造类型在运行时被使用时,类型参数的每次使用都由构造类型所提供的实际类型实参所代替。例如
139
140class C<v>
141
142{
143
144public V f1;
145
146public C<v> f2=null;
147
148
149
150
151public C(V x){
152
153this.f1 = x;
154
155this.f2 = this;
156
157}
158
159}
160
161class Application
162
163{
164
165static void Main (){
166
167C<int> x1= new C<int>(1);
168
169Console.WriteLine(x1.f1); // 打印 1
170
171C<double> x2 = new C<double>(3.1415);
172
173Console.WriteLine(x2.f1); // 打印 3.1415
174
175}
176
177}
178
179在实例函数成员之内, this 的类型就是声明的实例类型(§ 20.1.2)。
180
181除了使用类型参数作为类型和成员,在泛型类声明中也遵循和非泛型类成员相同的规则。适用于特定种类成员的附加规则将在后面几节进行讨论。
182
183### 20.1.5 泛型类中的静态字段
184
185在一个泛型类声明中的静态变量,在相同封闭构造类型(§ 20.5.2)所有实例中被共享,但在不同封闭构造类型的实例中 [1] ,是不被共享的。这些规则不管静态变量的类型包含那种类型参数都适用。
186
187例如
188
189class C<v>
190
191{
192
193static int count = 0;
194
195public C()
196
197{
198
199count++;
200
201}
202
203public static int Count{
204
205get{return count;}
206
207}
208
209}
210
211class Application
212
213{
214
215static void Main ()
216
217{
218
219C<int> x1 = new C<int>();
220
221Console.WriteLine(C<int>.Count);// 打印 1
222
223C<double> x2 = new C<double>();
224
225Console.WriteLine(C<int>.Count);// 打印 1
226
227C<int> x3 = new C<int>();
228
229Console.WriteLine(C<int>.Count);// 打印 2
230
231}
232
233}
234
235
236
237
238* * *
239
240[1] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如 List<int> 和 List<string> 这二者的实例是不能共享静态变量的。</string></int></int></int></int></int></double></double></int></int></int></v></double></double></int></int></v></v></int></string></string></v></v></u,v></t></int,t></t></string></string></v></u,v></v></u></t></u></t></t></t></u,v></v></int></t></list<string></int></t></t>