C # 2.0 specification (Generic III)

Source: Internet
Author: User

Second generic type

20.4 generic delegate declarations

A delegate declaration can contain type parameters.

Delegate-declaration:
attributes opt delegate-modifiers op t delegate return-type identifier type-parameter-list opt
(formal-parameter-list opt) type-parameter-constraints-clauses opt;
(Delegate declaration: attribute optional Delegate modifier optional delegate return type identifier type parameter list optional (formal parameter list optional) type parameter constraint statement optional
A delegate declared with a type parameter is a generic delegate declaration. A delegate declaration supports a type parameter constraint statement (§20.7) only when the type parameter list is supported. In addition to what is noted, generic delegate declarations and regular delegate declarations follow the same rules. Each type parameter in a generic delegate declaration defines a name in the specific declaration space (§3.3) associated with the delegate. The scope of the type parameter in the delegate declaration includes the return type, the formal argument list, and the type parameter constraint statement.

Like other generic type declarations, a type argument must be given to form a constructed delegate type. The parameters and return values of the constructed delegate type are formed by the argument substitution of each type parameter that constructs the delegate type in the delegate declaration. The result return type and parameter type are used to determine what method is compatible with the constructed delegate type. For example

delegate bool Predicate<t> (T Value) class x{static bool F (int i) {...} static bool G (string s) {...} static void Main () {predicate<int> p1 = F; Predicate<string> p2=g;}}

Note that the two assignments in the previous Main method are equivalent to the longer form below.

static void Main () {predicate<int> p1 = new predicate<int> (F); predicate<string> P2 = new predicate<string> (G);}

Because of the method group conversion, the shorter form is also possible, as described in §21.9.

20.5 Construction Types

A generic type declaration itself does not represent a type. Instead, generic type declarations are used to form many different types of "blueprints" by applying type arguments. The type parameter is written between the angle brackets and immediately after the generic type declaration name. A type that is named with at least one argument is called a constructed type (constructed type). A constructed type can be used in most places where a type name can occur in a language.

Type-name: (type name:) Namespace-or-type-name (namespace or type name) Namespace-or-type-name: (Namespace or type name:) identifier Type-argument-list (the identifier type argument list is optional) namespace-or-type-name. Identifier (namespace or type name. identifier) type-argument-list opt (type argument list optional)

A constructed type can also be used as a simple name (§20.9.3) in an expression or to access a member (§20.9.4).

When a namespace or type name is computed, only generic types with the correct number of type parameters are considered. Thus, it is possible to identify different types with the same identifier, as long as the types have different number of type parameters and are declared in different namespaces. This is useful for mixing generics and non-generic classes in the same program.

Namespace System.collections{class queue{...}} Namespace Sysetm.collections.generic{class queue<elementtype>{...}} namespace myapplication{using system.collections;using system.collections.generic;class X{Queue Q1;// System.collections.queuequeue<int> Q2;//system.collections.generic.queue}}

The detailed rules for name lookups in these codes are described in §20.9. The ambiguity resolution in these codes is described in §20.6.5.

A type name may identify a constructed type, although it does not directly specify a type parameter. This occurs when a type is nested within a generic class declaration, and the instance type that contains the declaration is implicitly used because of the name lookup (§20.1.2).

Class Outer<t>{public class inner{...} public Inner i; The type of I is outer<t>. Inner}

In unsafe code, a constructed type cannot be used as an unmanaged type (§18.2).

20.5.1 type arguments

Each argument in a type parameter list is just a type.

Type-argument-list: (Type argument list:) <type-arguments> (< type argument >) type-arguments: (type argument:) type-argument (type argument) type-arguments, type-argument (type argument, type argument) Type-argument: (type argument:) type (type)


A type argument can, in turn, be a constructed type or a type parameter. In unsafe code (§18), type arguments cannot be pointer types. Each type argument must follow any constraints on the corresponding type parameter (§20.7.1).

20.5.2 Open and closed types

All types can be classified as open type or enclosing type (closed type). An open type is a type that contains a type parameter. More specifically,

The type parameter defines an open type

An array type is an open type only if its element is an open type

A constructed type is an open type only if one or more of its type arguments are open types


Non-open types are enclosing types.



At run time, all code in a generic type declaration executes in the context of an enclosing constructed type, which is created by applying a type argument to the generic declaration. Each type argument in a generic type is bound to a specific run-time type. The run-time processing of all statements and expressions always occurs for the enclosing type, while the open type only occurs at compile-time processing.

Each enclosing constructed type has its own set of static variables that are not shared by other enclosing types. Because there is no open type at run time, there is no static variable associated with the open type. If two enclosing constructed types are constructed from the same type declaration, and the corresponding type arguments are the same type, then they are the same type.

20.5.3 base classes and interfaces for constructed types

A constructed class type has a direct base class, which is like a simple class type. If a generic class declaration does not specify a base class, its base class is object. If a base class is specified in a generic class declaration, the base class of the constructed type is obtained by substituting each type parameter in the base class declaration with the corresponding type argument of the constructed type. Given generic class declaration

Class B<u, v>{...} Class G<t>:b<string, t[]>{...}

The base class for the constructed type g<int> will be b<string, int[]>.

Similarly, the construction class, struct, and interface types have a set of explicit base interfaces. An explicit base interface is formed by accepting an explicit base interface declaration and an alternative in a generic type declaration, which is substituted for each type parameter in the base interface declaration as the corresponding type argument of the constructed type.



All base classes and base interfaces of a type are formed by recursively getting the base class and interface of the intermediate base class and interface. For example, given a generic class declaration

Class A {...} Class b<t>:a{...} Class c<t>:b<icomparable<t>>{...} Class d<t>:c<t[]>{...} The base class for d<int> is C<int[]>,b<icomparable<int[]>>,a and object.

20.5.4 members of a constructed type

A non-inherited member of a constructed type is obtained by overriding the type argument of a member declaration, constructing the corresponding type argument of the type.

For example, given a generic class declaration

Class gen<t,u>{public t[,],a;public void G (int i, T T, Gen<u, t> gt) {...} Public U Prop (get{...}) set{...} public int h{double d}{...}}

The constructed type gen<int[],icomparable<string>> as a member below.

Public int[,][] a;public void G (int I, int[] t, gen<icomparable<string>,int[] gt>) {...} Public icomparable<string> prop{get{...} set{...} public int H (double d) {...}

Note that alternative processing is based on the semantic meaning of type declarations and is not a simple text-based alternative. In a generic class declaration, the type of member A in Gen A is a two-dimensional array of T, so the type of member A in the previously instantiated type is a two-dimensional array of type int's one-dimensional array or int[,][].

Inherited members of a constructed type are obtained in a similar way. First, all members of the direct base class are already determined. If the base class itself is a constructed type, this may include the recursive application of the current rule. Each of the inherited members is then converted by substituting each type parameter in the member declaration for the type argument of the constructed type.

Class B<u>{public U F (long index) {...}} Class D<t>:b<t[]>{public T G (string s) {...}}

In the previous example, the non-inherited member public int G (string s) of the constructed type d<int> is obtained by substituting the type argument int of the type parameter T. D<int> also has an inherited member that comes from class declaration B. This inherited member is determined by first determining the members of the construction type b<t[]> that the,b<t[]> member is determined by replacing the U with t[], which produces the public t[] F (long index). The type argument int then replaces the type parameter T, resulting in the inherited member public int[] F (long index).

20.5.5 accessibility of constructed types

When the constructed type C<t1,..., all parts of the tn> c,t1,..., TN is accessible, then it is accessible. For example, if the generic type name C is public, and all type parameters T1,..., TN is also public, then the accessibility of the constructed type is also public. If one of the type names or type arguments is private, the accessibility of the constructed type is private. If one of the type arguments is protected and the other is internal, then the accessibility of the constructed type is limited to that class, as well as the subclasses within the Assembly.

20.5.6 Conversion

The constructed type follows the same rules as the non-generic type (§6). When these rules are applied, the base class and interface of the constructed type must be determined in the same manner as described in §20.5.3.

In addition to those described in §6, there is no special conversion between constructed reference types. In particular, unlike array types, constructed reference types do not allow "co-variant" conversions. That is, type list<b> cannot be converted to type list<a> (either implicitly or explicitly) even if B is derived from a. Similarly, there is no conversion from list<b> to list<object>.

The rationale for this is simple: if you can convert to List<a>, it is clear that you can store a value of type a into the list. This will break the invariance of the value of type B for each object in the list<b> type, or an unexpected error when assigning a value on the collection class.

The behavior of the transformation and the run-time type check are shown below.

Class A {...} Class b:a{...} Class colletion{...} Class list<t>:collection{...} Class Test{void F () {list<a> ListA = new list<a> (); list<b> listb= new list<b> (); Collection C1 = ListA; Ok,list<a> is a set collection C2 = Listb; Ok,list<b> is a set list<a> a1 = Listb; Error, no implicit conversion list<a> a2 = (list<a>) Listb; Error, no explicit conversion}}

20.5.7system.nullable<t> type

A generic struct type system.nullable<t> generic struct type is defined in the. NET base Class library, which indicates that a value of type T can be null. The system.nullable<t> type is useful in many situations, such as a nullable column that indicates a database table, or an optional attribute in an XML element.

You can implicitly convert from a null type to any type constructed by the system.nullable<t> type. The result of this conversion is the default value of System.nullable<t>. In other words, it can be written

Nullable<int> x = null; Nullable<string> y = null;

The same as the following notation.

nullable<int> x = nullable<int>.default; Nullable<string> y = nullable<string>.default;

20.5.8 using alias directives

You can use aliases to name an enclosing constructed type, but you cannot name a generic type declaration that does not provide a type argument. For example

namespace N1{class a<t>{class b{}}class c{}}namespace n2{using W = N1. A Error, cannot name a generic type using X = N1. A.B; Error, cannot name a generic type using Y = N1. a<int>; OK, you can name the enclosing constructed type using Z = N1. C Ok

20.5.9 characteristics

An open type cannot be used anywhere within an attribute. A closed constructed type can be used as an argument to an attribute, but cannot be used as an attribute name because System.Attribute cannot be the base class for a generic class declaration.

Class A:attribute{public A (Type t) {...}} Class B<t>: attribute{}//error, cannot use Attribute as base class List<t>{[a (typeof (T))] t T;//error, there is an open type in attribute}class X {[A ( typeof (List<int>))] int x; OK, closed construction type [b<int>] int y; Error, invalid attribute name}

The above is C # 2.0 specification (generic three) content, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.