20.1.6泛型类中的静态构造函数
在泛型类中的静态构造函数被用于初始化静态字段,为每个从特定泛型类声明中创建的不同的封闭构造类型,执行其他初始化。泛型类型声明的类型参数在作用域之内,可以在静态构造函数体内被使用。
如果下列情形之一发生,一个新的封闭构造类类型将被首次初始化。
一个封闭构造类型的实例被创建时
封闭构造类型的任何静态成员被引用时
为了初始化一个新的封闭的构造类类型,首先那个特定封闭类型的一组新静态字段(§20.1.5)将会被创建。每个静态字段都被初始化为其默认值(§5.2)。接着,静态字段初始化器(§10.4.5.1)将为这些静态字段执行。最后静态构造函数将被执行。
由于静态构造函数将为每个封闭构造类类型执行一次,那么在不能通过约束(§20.7)检查的类型参数上实施运行时检查,将会很方便。例如,下面的类型使用一个静态构造函数检查一个类型参数是否是一个引用类型。
class Gen<T>{static Gen(){if((object)T.default != null){throw new ArgumentException(“T must be a reference type”);}}}
20.1.7 访问受保护的成员
在一个泛型类声明中,对于继承的受保护的实例成员的访问是允许的,通过从泛型类构造的任何类型的实例就可以做到。尤其是,用于访问§3.5.3中指定的protected和protected internal实例成员的规则,对于泛型使用如下的规则进行了扩充。
在一个泛型类G中,对于一个继承的受保护的实例成员M,使用E.M的基本表达式是允许的,前提是E的类型是一个从G构造的类类型,或继承于一个从G构造的类类型的类类型。
在例子
class C<T>{protected T x;}class D<T> :C<T>{static void F(){D<T> dt = new D<T>();D<int> di = new D<int>();D<string> ds = new D<string>();dt.x = T.default;di.x = 123;ds.x = “test”;}}
三个对x的赋值语句都是允许的,因为它们都通过从泛型构造的类类型的实例发生。
20.1.8在泛型类中重载
在一个泛型类声明中的方法、构造函数、索引器和运算符可以被重载。但为了避免在构造类中的歧义,这些重载是受约束的。在同一个泛型类声明中使用相同的名字声明的两个函数成员必须具有这样的参数类型,也就是封闭构造类型中不能出现两个成员使用相同的名字和签名。当考虑所有可能的封本文来源gaodai#ma#com搞*!代#%^码$网!闭构造类型时,这条规则包含了在当前程序中目前不存在的类型是实参,但它仍然是可能出现的[1]。在类型参数上的类型约束由于这条规则的目的而被忽略了。
下面的例子根据这条规则展示了有效和无效的重载。
nterface I1<T> {…}interface I2<T>{…}class G1<U>{long F1(U u); //无效重载,G<int>将会有使用相同签名的两个成员int F1(int i);void F2(U u1, U u2); //有效重载,对于U没有类型参数void F2(int I , string s); //可能同时是int和string void F3(I1<U>a); //有效重载void F3(I2<U>a);void F4(U a); //有效重载void F4(U[] a);}class G2<U,V>{void F5(U u , V v); //无效重载,G2<int , int>将会有两个签名相同的成员void F5(V v, U u);void F6(U u , I1<V> v);//无效重载,G2<I1<int>,int>将会有两个签名相同的成员void F6(I1<V> v , U u);void F7(U u1,I1<V> V2);//有效的重载,U不可能同时是V和I1<V>void F7(V v1 , U u2);void F8(ref U u); //无效重载void F8(out V v);}class C1{…}class C2{…}class G3<U , V> where U:C1 where V:C2{void F9(U u); //无效重载,当检查重载时,在U和V上的约束将被忽略void F9(V v);}
0.1.9参数数组方法和类型参数