C#2.0 Specification(泛型一)

类别:.NET开发 点击:0 评论:0 推荐:

这篇文章是翻译的微软的技术文章.供学习c#的朋友参考,请勿用于商业目的。http://msdn.microsoft.com/vcsharp/team/language/default.aspx

由于这一章非常长可能需要分几篇:)

20.泛型

20.1泛型类声明

泛型类声明是一个需要提供类型参数以形成实际类型的类的声明。

 

类声明可以有选择地定义类型参数。

class-declaration: (类声明)

attributesopt class-modifiersopt  class identifieropt  type-parameter-listopt  class –baseopt  type-parameter-constraints-clauseopt  class-body;opt  (特性可选  类修饰符可选  类标识符可选  类型参数列表可选  基类可选    类型参数约束语句可选    类体; 可选  )

 除非提供了类型参数列表,类声明可以不提供类型参数化约束语句。

提供了类型参数列表的类声明是一个泛型类声明。此外,任何嵌入到泛型类声明或泛型结构声明中的类,自身是一个泛型类声明,因为必须提供包含类型的类型参数以创建构造类型(constructed type);

泛型类通过使用构造类型而被引用(§20.5)。给定泛型类声明

class List<T>{}

这是构造类型的一些例子,List<T>List<int>List<List<string>>。构造类型可以使用一个或多个参数,例如List<T>被称为开放构造类型(open constructed type。不使用类型参数的构造类型,例如List<int>被称为封闭构造类型(closed constructed type

 

泛型类型不可以被“重载”;也就是说,和普通类型一样在一个作用域内,泛型类型必须被唯一地命名。


 

class C{}

class C<V>{}//错误,C定义了两次

class C<U,V>{}//错误,C定义了两次

然而在非限定类型名字查找(§20.9.3)中使用的类型查找规则和成员访问(§20.9.4),确实考虑到了类型参数的个数。

20.1.1类型参数

类型参数可以在一个类声明上提供。每个类型参数是一个简单的标识符,它指示了用来创建一个构造类型的类型参数的占位符。类型参数是在后面将要被提供的类型的形式占位符。相反,类型参数§20.5.1)只是在构造类型被引用时,实际类型的一个替代。

 

type-parameter-list:(类型参数列表:)

              <type-parameters> <类型参数>

type-parameters:(类型参数:)

       type-parameter(类型参数)

       type-parameters type-parameter(类型参数,类型参数)

type-parameter:(类型参数:)

       attributesopt identifier(特性可选 标识符)

 

在类声明中的每个类型参数在类的声明空间(§3.3)定义了一个名字。由此,它不能和另一个类型参数或在类中声明的成员有同样的名字。类型参数不能和类型自身有同样的名字。

在一个类中的类型参数的作用域(§3.7),包括基类 、 类型参数约束语句和类体。不像类的成员,它没有扩展到派生类。在其作用域之内,类型参数可以被用作一个类型。

type(类型):

       value-type(值类型)

       reference-type(引用类型)

       type-parameter(类型参数)

由于类型参数可以被许多不同的实际类型实参所实例化,类型参数与其他类型相比将略微有一些不同的操作和限制。包括如下内容。

  • 类型参数不能用于直接声明一个基类型或者接口
  • 对于在类型参数上的成员查找规则,如果约束存在,则依赖于应用到该类型参数的约束。更详细地说明参看§20.7.4

 


  • 类型参数可行的转换依赖于应用到该类型参数上的约束(如果有的话)。详细地说明参看§20.7.4
  • 字面null不能被转换到由类型参数所给定的类型,除非类型参数是由一个类约束(§20.7.4)所约束。然而可以使用一个默认值表达式(§20.8.1)代替。此外,由一个类型参数给定的类型的值可以使用“==”和“!=”(§20.8.4)与null进行比较。
  • 如果类型参数通过一个构造函数约束(constructor-constraint)(§20.7)而约束,new表达式只能用过一个类型参数而被使用。
  • 类型参数不能用于特性内的任何地方。
  • 类型参数不能用于成员访问,或者表示一个静态成员或者嵌套类型的类型名字(§20.9.1、§20.9.4)。
  • 在不安全代码中,类型参数不能被用作托管类型(§18.2)。

作为一种类型,类型参数纯粹只是一个编译时构件。在运行时,每个类型参数被绑定到运行时类型,它是通过泛型类型声明所提供的类型实参所指定的。为此,在运行时,使用类型参数声明的变量类型是一个封闭类型(closed type)(§20.5.2)。所有语句和表达式在运行时执行所使用的类型参数,都是由那个参数作为类型实参而提供的实际类型。

20.1.2实例类型

每个类声明都有与之关联的构造类型,即实例类型(instance type)对于一个泛型类声明,实例类型通过创建一个来自于类型声明的构造类型(§20.4)而形成,它使用对应于类型参数的每一个类型实参。由于实例化类型使用类型参数,在类型参数作用域内(类声明之内),它是唯一有效的。实例类型在类声明中是this的类型。对于非泛型类,实例类型只是一个声明类型。下面展示了几个声明类,以及它们的实例类型。

class A<T>      //实例类型:A<T>

{

    class B{}       //实例类型:A<T>.B

    class C<U>{}        //实例类型:A<T>.C<U>

}

class D{}       //实例类型:D

 

20.1.3基类规范

在类声明中指定的基类可以是一个构造类型(§20.5)。一个基类其自身不能是一个类型参数,但在其作用域内可以包含类型参数。

 


class Extend<V>: V{}//错误,类型参数被用作基类

泛型类声明不能使用System.Attribute作为直接或间接基类。

在一个类声明中指定的基接口可以是构造接口类型(§20.5)。基接口自身不能是类型参数,但在其作用域内可以包含类型参数,下面的代码演示了如何实现和扩展构造类型。

class C<U,V>{}

Interface I1<V>{}

class D:C<string  , int>,I1<string>{}

class E<T>:C<int,T> ,I1<T>{}

泛型类型声明的基接口必须满足§20.3.1中所描述的唯一性规则。

从基类或接口重写或实现方法的类的方法,必须提供特定类型的合适方法。下面的代码演示了方法如何被重写和实现。这将会在§20.1.10中进一步解释。

class C<U,V>

{

    public virtual void  M1(U x , List<V> y){…}

}

interface I1<V>

{

    V  M2(V x);

}

class D:C<string  , int>,I1<string>

{

    public override void M1(string x , List<int> y){…}

    public string M2(string x){…}

}

 

20.1.4泛型类的成员

泛型类的所有成员都可以直接地或者作为构造类型的一部分,从任何封闭类(enclosing class)中使用类型参数。当特定的封闭构造类型在运行时被使用时,类型参数的每次使用都由构造类型所提供的实际类型实参所代替。例如

 

class C<V>

{  

    public V f1;   

    public C<V> f2=null;

 


    public C(V x){

this.f1 = x;

this.f2 = this;

}

}

class Application

{

    static void Main(){

C<int> x1= new C<int >(1);

Console.WriteLine(x1.f1);  //打印1

C<double> x2 = new C<double>(3.1415);

Console.WriteLine(x2.f1); //打印 3.1415

}

}

在实例函数成员之内,this的类型就是声明的实例类型(§20.1.2)。

除了使用类型参数作为类型和成员,在泛型类声明中也遵循和非泛型类成员相同的规则。适用于特定种类成员的附加规则将在后面几节进行讨论。

20.1.5泛型类中的静态字段

在一个泛型类声明中的静态变量,在相同封闭构造类型(§20.5.2)所有实例中被共享,但在不同封闭构造类型的实例中[1],是不被共享的。这些规则不管静态变量的类型包含那种类型参数都适用。

例如

class C<V>

{

    static int count = 0;

    public C()

{

count++;

}

public static int Count{

get{return count;}

}

}

class Application

{

       static void Main()

{

C<int> x1 = new C<int>();

Console.WriteLine(C<int>.Count);//打印 1

C<double> x2 = new C<double>();

Console.WriteLine(C<int>.Count);//打印 1

C<int> x3 = new C<int>();

Console.WriteLine(C<int>.Count);//打印 2

}

}



[1] 这是很容易理解的,因为在运行时,不同的封闭构造类型,是属于不同的类型,比如List<int> List<string> 这二者的实例是不能共享静态变量的。

本文地址:http://com.8s8s.com/it/it45137.htm