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

Chapter 26 Generics

1class C<T>

2{

3protected T x;

4}

5class D<T>: C<T>

6{

7

static void F() {

8

D<T> dt = new D<T>();

9

D<int> di = new D<int>();

10

D<string> ds = new D<string>();

11

dt.x = default(T);

12

di.x = 123;

13

ds.x = "test";

14}

15}

16the three assignments to x are permitted because they all take place through instances of class types

17constructed from the generic type. end example]

1826.1.7 Overloading in generic classes

19Methods, constructors, indexers, and operators within a generic class declaration can be overloaded;

20however, overloading is constrained so that ambiguities cannot occur within constructed classes. Two

21function members declared with the same names in the same generic class declaration shall have parameter

22types such that no closed constructed type could have two members with the same name and signature.

23When considering all possible closed constructed types, this rule includes type arguments that do not

24currently exist in the current program, but could be written. Type constraints (§26.7) on the type parameter

25are ignored for the purpose of this rule.

26[Example: The following examples show overloads that are valid and invalid according to this rule:

27interface I1<T> {…}

28interface I2<T> {…}

29class G1<U>

30{

31

long F1(U u) {…}

//

Invalid overload, G<int> would have two

32

int F1(int i) {…}

//

members with the same signature

33

void F2(U u1, U u2) {…} // Valid overload, no type argument for U

34

void F2(int i, string s) {…}

35

 

// could be int and string simultaneously

36

void F3(I1<U> a) {…}

// Valid overload

37

void F3(I2<U> a) {…}

 

 

38

void F4(U a) {…}

// Valid overload

39void F4(U[] a) {…}

40}

41class G2<U, V>

42{

43

void F5(U u, V v) {…}

// Invalid overload, G2<int, int> would

44

void F5(V v, U u) {…}

// have two members with the same

45

 

// signature

46

void F6(U u, I1<V> v) {…}

// Invalid overload, G2<I1<int>, int>

47

 

// would have two members with the

48

void F6(I1<V> v, U u) {…}

// same signature

49

void F7(U u1, I1<V> v2) {…}

// Valid overload, U cannot be V <V>

50

void F7(V v1, U u2) {…}

// and I1 simultaneously

51

void F8(ref U u) {…}

// Invalid overload

52void F8(out V v) {…}

53}

54class C1 {…}

55class C2 {…}

401

C# LANGUAGE SPECIFICATION

1class G3<U, V> where U: C1 where V: C2

2{

3

void

F9(U

u)

{…}

//

Invalid overload, constraints on U and V

4

void

F9(V

v)

{…}

//

are ignored when checking overloads

5}

6end example]

726.1.8 Parameter array methods and type parameters

8Type parameters can be used in the type of a parameter array. [Example: Given the declaration

9class C<V>

10{

11static void F(int x, int y, params V[] args) { … }

12}

13the following invocations of the expanded form of the method:

14C<int>.F(10, 20);

15C<object>.F(10, 20, 30, 40);

16C<string>.F(10, 20, "hello", "goodbye");

17correspond exactly to:

18C<int>.F(10, 20, new int[] {});

19C<object>.F(10, 20, new object[] {30, 40});

20C<string>.F(10, 20, new string[] {"hello", "goodbye"} );

21end example]

2226.1.9 Overriding and generic classes

23Function members in generic classes can override function members in base classes, as usual. If the base

24class is a non-generic type or a closed constructed type, then any overriding function member cannot have

25constituent types that involve type parameters. When determining the overridden base member, the members

26of the base classes shall be determined by substituting type arguments, as described in §26.5.4. Once the

27members of the base classes are determined, the rules for overriding are the same as for non-generic classes.

28[Example: The following example demonstrates how the overriding rules work in the presence of generics:

29abstract class C<T>

30{

31

public

virtual

T F() {…}

32

public

virtual

C<T> G() {…}

33public virtual void H(C<T> x) {…}

34}

35class D: C<string>

36{

37

public override string F() {…}

// Ok

38

public override C<string> G() {…}

// Ok

39

public override void H(C<int> x) {…}

// Error, should be C<string>

40}

41class E<T, U>: C<U>

42{

43

public override U F() {…}

// Ok

44

public override C<U> G() {…}

// Ok

45

public override void H(C<T> x) {…}

// Error, should be C<U>

46}

47end example]

4826.1.10 Operators in generic classes

49Generic class declarations can define operators, following the same rules as non-generic class declarations.

50The instance type (§26.1.2) of the class declaration shall be used in the declaration of operators in a manner

51analogous to the normal rules for operators, as follows:

402

Chapter 26 Generics

1A unary operator shall take a single parameter of the instance type. The unary ++ and -- operators shall

2return the instance type or a type derived from the instance type.

3At least one of the parameters of a binary operator shall be of the instance type.

4Either the parameter type or the return type of a conversion operator shall be of the instance type.

5[Example: The following shows some examples of valid operator declarations in a generic class:

6class X<T>

7{

8

public

static

X<T> operator ++(X<T> operand) {…}

9

public

static

int operator *(X<T> op1, int op2) {…}

10public static explicit operator X<T>(T value) {…}

11}

12end example]

13For a conversion operator that converts from a source type S to a target type T, when the rules specified in

14§17.9.3 are applied, any type parameters associated with S or T are considered to be unique types that have

15no inheritance relationship with other types, and any constraints on those type parameters are ignored.

16[Example: In the following code

17class C<T> {…}

18class D<T>: C<T>

19{

20

public

static

implicit

operator

C<int>(D<T> value) {…}

// Ok

21

public

static

implicit

operator

C<T>(D<T> value) {…}

// Error

22}

23the first operator declaration is permitted because, for the purposes of §17.9.3, T and int are considered

24unique types with no relationship. However, the second operator is an error because C<T> is the base class

25of D<T>. end example]

26It is possible to declare operators that, for some type arguments, specify conversions that already exist as

27pre-defined conversions. [Example: In the following code

28struct Convertible<T>

29{

30

public static implicit operator Convertible<T>(T value) {…}

31public static explicit operator T(Convertible<T> value) {…}

32}

33when type object is specified as a type argument for T, the second operator declares a conversion that

34already exists (an implicit, and therefore also an explicit, conversion exists from any type to type object).

35end example]

36In cases where a pre-defined conversion exists between two types, any user-defined conversions between

37those types are ignored. Specifically:

38If a pre-defined implicit conversion (§13.1) exists from type S to type T, all user-defined conversions

39(implicit or explicit) from S to T are ignored.

40If a pre-defined explicit conversion (§13.2) exists from type S to type T, any user-defined explicit

41conversions from S to T are ignored. However, user-defined implicit conversions from S to T are still

42considered.

43[Example: For all types but object, the operators declared by the Convertible<T> type above do not

44conflict with pre-defined conversions. For example:

45void F(int i, Convertible<int> n) {

46

i = n;

// Error

47

i = (int)n;

// User-defined explicit conversion

48

n = i;

// User-defined implicit conversion

49

n = (Convertible<int>)i;

// User-defined implicit conversion

50

}

 

403

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