Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C-sharp language specification.2004.pdf
Скачиваний:
14
Добавлен:
23.08.2013
Размер:
2.55 Mб
Скачать

Chapter 26 Generics

1resulting return type and parameter types are used in determining what methods are consistent (§22.1) with a

2constructed delegate type. [Example:

3delegate bool Predicate<T>(T value);

4class X

5{

6

static void Main() {

7

Predicate<int> p1 =

8

delegate(int i) {

9

//...

10

};

11

Predicate<string> p2 =

12

delegate(string s) {

13

//...

14

};

15}

16}

17end example]

1826.5 Constructed types

19A generic type declaration, by itself, denotes an unbound generic type that is used as a “blueprint” to form

20many different types, by way of applying type arguments. The type arguments are written within angle

21brackets (< and >) immediately following the name of the generic type declaration. A type that is named

22with at least one type argument is called a constructed type. A constructed type can be used in most places

23in the language in which a type name can appear. An unbound generic type can only be used within a typeof-

24expression (§14.5.11).

25Constructed types can also be used in expressions as simple names (§14.5.2) or when accessing a member

26(§14.5.4).

27When a namespace-or-type-name is evaluated, only generic types with the correct number of type

28parameters are considered. Thus, it is possible to use the same identifier to identify different types, as long as

29the types have different numbers of type parameters. This is useful when mixing generic and non-generic

30classes in the same program. [Example:

31namespace Widgets

32{

33

class Queue {…}

34class Queue<ElementType> {…}

35}

36namespace MyApplication

37{

38

using Widgets;

 

39

class X

 

40

{

 

41

Queue q1;

//Non-generic Widgets.Queue

42

Queue<int> q2;

// Generic Widgets.Queue

43}

44}

45end example]

46The detailed rules for name lookup in the namespace-or-typename productions is described in §10.8. The

47resolution of ambiguities in these productions is described in §9.2.3.

48A type-name might identify a constructed type even though it doesn’t specify type parameters directly. This

49can occur where a type is nested within a generic class declaration, and the instance type of the containing

50declaration is implicitly used for name lookup (§26.1.11). [Example:

407

C# LANGUAGE SPECIFICATION

1class Outer<T>

2{

3

public

class

Inner {…}

 

4

public

Inner

i;

// Type of i is Outer<T>.Inner

5}

6end example]

7[Note: In unsafe code, a constructed type shall not be used as an unmanaged-type (§25.2). end note]

826.5.1 Type arguments

9Each argument in a type argument list is simply a type.

10type-argument-list:

11< type-arguments >

12type-arguments:

13

type-argument

14

type-arguments , type-argument

15

type-argument:

16

type

17Type arguments can be constructed types or type parameters. [Note: In unsafe code (§25), a type-argument

18shall not be a pointer-type. end note] Each type argument shall satisfy any constraints on the corresponding

19type parameter (§26.7.1).

2026.5.2 Open and closed types

21All types can be classified as either open types or closed types. An open type is a type that involves type

22parameters. More specifically:

23A type parameter defines an open type.

24An array type is an open type if and only if its element type is an open type.

25A constructed type is an open type if and only if one or more of its type arguments is an open type. A

26constructed nested type is an open type if and only if one or more of its type arguments or the type

27arguments of its containing type(s) is an open type.

28A closed type is a type that is not an open type.

29At run-time, all of the code within a generic type declaration is executed in the context of a closed

30constructed type that was created by applying type arguments to the generic declaration. Each type

31parameter within the generic type is bound to a particular run-time type. The run-time processing of all

32statements and expressions always occurs with closed types, and open types occur only during compile-time

33processing.

34Each closed constructed type has its own set of static variables, which are not shared with any other closed

35constructed types. Since an open type does not exist at run-time, there are no static variables associated with

36an open type. Two closed constructed types are the same type if they are constructed from the same unbound

37generic type, and their corresponding type arguments are the same type.

3826.5.3 Base classes and interfaces of a constructed type

39A constructed class type has a direct base class, just like a simple class type. If the generic class declaration

40does not specify a base class, the base class is object. If a base class is specified in the generic class

41declaration, the base class of the constructed type is obtained by substituting, for each type-parameter in the

42base class declaration, the corresponding type-argument of the constructed type. [Example: Given the

43generic class declarations

44class B<U,V> {…}

45class G<T>: B<string,T[]> {…}

408

Chapter 26 Generics

1the base class of the constructed type G<int> would be B<string,int[]>. end example]

2Similarly, constructed class, struct, and interface types have a set of explicit base interfaces. The explicit

3base interfaces are formed by taking the explicit base interface declarations on the generic type declaration,

4and substituting, for each type-parameter in the base interface declaration, the corresponding type-argument

5of the constructed type.

6The set of all base classes and base interfaces for a type is formed, as usual, by recursively getting the base

7classes and interfaces of the immediate base classes and interfaces. [Example: Given the generic class

8declarations:

9class A {…}

10class B<T>: A {…}

11class C<T>: B<IComparable<T>> {…}

12class D<T>: C<T[]> {…}

13the base classes of D<int> are C<int[]>, B<IComparable<int[]>>, A, and object. end example]

1426.5.4 Members of a constructed type

15The non-inherited members of a constructed type are obtained by substituting, for each type-parameter in

16the member declaration, the corresponding type-argument of the constructed type. The substitution process

17is based on the semantic meaning of type declarations, and is not simply textual substitution.

18[Example: Given the generic class declaration

19class Gen<T,U>

20{

21

public T[,] a;

22

public void G(int i, T t, Gen<U,T> gt) {…}

23

public U Prop { get {…} set {…} }

24public int H(double d) {…}

25}

26the constructed type Gen<int[],IComparable<string>> has the following members:

27public int[,][] a;

28public void G(int i, int[] t, Gen<IComparable<string>,int[]> gt) {…}

29public IComparable<string> Prop { get {…} set {…} }

30public int H(double d) {…}

31The type of the member a in the generic class declaration Gen is “two-dimensional array of T”, so the type

32of the member a in the constructed type above is “two-dimensional array of one-dimensional array of int”,

33or int[,][]. end example]

34The inherited members of a constructed type are obtained in a similar way. First, all the members of the

35immediate base class are determined. If the base class is itself a constructed type, this might involve a

36recursive application of the current rule. Then, each of the inherited members is transformed by substituting,

37for each type-parameter in the member declaration, the corresponding type-argument of the constructed

38type. [Example:

39class B<U>

40{

41public U F(long index) {…}

42}

43class D<T>: B<T[]>

44{

45public T G(string s) {…}

46}

47In the above example, the constructed type D<int> has a non-inherited member public int G(string

48s) obtained by substituting the type argument int for the type parameter T. D<int> also has an inherited

409

C# LANGUAGE SPECIFICATION

1member from the class declaration B. This inherited member is determined by first determining the members

2of the constructed type B<T[]> by substituting T[] for U, yielding public T[] F(long index). Then, the

3type argument int is substituted for the type parameter T, yielding the inherited member public int[]

4F(long index). end example]

526.5.5 Accessibility of a constructed type

6A constructed type C<T1, ...,TN> is accessible when all of its components C, T1, ..., TN are accessible. More

7precisely, the accessibility domain for a constructed type is the intersection of the accessibility domain of the

8unbound generic type and the accessibility domains of the type arguments.

926.5.6 Conversions

10Constructed types follow the same conversion rules (§13) as do non-generic types. When applying these

11rules, the base classes and interfaces of constructed types shall be determined as described in §26.5.3.

12No special conversions exist between constructed reference types other than those described in §13. In

13particular, unlike array types, constructed reference types do not exhibit “co-variant” conversions. This

14means that a type List<B> has no conversion (either implicit or explicit) to List<A> even if B is derived

15from A. Likewise, no conversion exists from List<B> to List<object>.

16[Note: The rationale for this is simple: if a conversion to List<A> is permitted, then apparently one can

17store values of type A into the list. But this would break the invariant that every object in a list of type

18List<B> is always a value of type B, or else unexpected failures can occur when assigning into collection

19classes. end note]

20[Example: The behavior of conversions and runtime type checks is illustrated below:

21class A {…}

22class B: A {…}

23class Collection {…}

24class List<T>: Collection {…}

25class Test

26{

27

void F() {

 

 

 

 

28

List<A> listA = new List<A>();

 

29

List<B> listB = new List<B>();

 

30

Collection

c1

= listA;

// Ok, List<A> is a Collection

31

Collection

c2

= listB;

// Ok, List<B> is a Collection

32

List<A>

a1

= listB;

// Error, no implicit conversion

33

List<A>

a2

= (List<A>)listB;

// Error, no explicit conversion

34}

35}

36end example]

3726.5.7 Using alias directives

38Using aliases can name a closed constructed type, but shall not name a generic type declaration without

39supplying type arguments. [Example:

40namespace N1

41{

42

class A<T>

43

{

44

class B {}

45}

46}

47namespace N2

48{

49

using W = N1.A;

// Error, cannot name generic type

410

Соседние файлы в предмете Электротехника