Connect Type Two
This article is a technical article of the translation of Microsoft. For the reference of Friends of C #, please do not use for commercial purposes. Http://msdn.microsoft.com/vcsharp/team/language/default.aspx
20.4 generic Delegate Declaration
A delegate declaration can contain a type parameter.
Delegate-declaration:
attributes opt delegate-modifiers op t delegate return-type identifier type-parameter-list opt
(Delegate declaration: attribute optional Delegate modifier optional delegate return type identifier type argument list optional (formal argument list optional) type parameter constraint statement optional
A delegate declared with a type parameter is a generic delegate declaration. A delegate declaration can support a type parameter constraint statement (§20.7) only if the type parameter list is supported. In addition to what is indicated, 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 a type parameter in a delegate declaration includes a return type, a formal argument list, and a type parameter constraint statement.
Like other generic type declarations, a type argument must be given to form a constructed delegate type. Constructs the parameters and return values of the delegate type, which are formed by substitution of the arguments for each type parameter of the constructor 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, a shorter form is also possible, which is illustrated in §21.9.
20.5 Construction Types
A generic type declaration itself does not represent a type. Instead, a generic type declaration is used to form many different types of "blueprints" by applying type arguments. The type parameter is written between the angle brackets and follows 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 the type name can appear in the 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 (optional identifier type argument list)
Namespace-or-type-name. Identifier (namespace or type name. identifier)
Type-argument-list opt (optional type argument list)
A constructed type can also be used in an expression as a simple name (§20.9.3) or to access a member (§20.9.4).
When a namespace or type name is evaluated, only generic types with the correct number of type parameters are considered. Thus, it is possible to identify different types using the same identifier as long as the type has different number of type parameters and is declared in a different namespace. This is useful for mixing generic 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.Queue
Queue<int> Q2;//system.collections.generic.queue
}
}
The detailed rules for name lookup in these codes are described in §20.9. The ambiguity resolution in these codes is described in the §20.6.5.
A type name may identify a constructed type, although it does not directly specify a type parameter. This situation 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 argument
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 (types)
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 type
All types can be divided into open types (open type) or enclosing type (closed type). An open type is a type that contains a type parameter. The more specific statement is that
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 all enclosing types.
At run time, all code in a generic type declaration executes in the context of a enclosing constructed type, which is created by applying the type arguments 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 closed types, whereas open types occur only 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, the open type has no static variables associated with it. If two enclosing constructed types are constructed from the same type declaration, and the corresponding type arguments are of the same type, they are the same type.
base classes and interfaces for 20.5.3 constructed types
A constructed class type has a direct base class, just like a simple class type. If the generic class declaration does not specify a base class, its base class is object. If the 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 for the type argument for the constructed type. Given generic class declaration
Class B<u, v>{...}
Class G<t>:b<string, t[]>{...}
The base class of the constructed type g<int> will be b<string, int[]>.
Similarly, a constructed class, struct, and interface type has a set of explicit base interfaces. An explicit base interface is formed by accepting the explicit base interface declaration and some substitution in a generic type declaration, which replaces each type parameter in the base interface declaration with the corresponding type argument of the constructed type.
All base classes and base interfaces of a type are formed by recursively obtaining the base classes and interfaces of the intermediate base classes and interfaces. 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 a member of a constructed type
A non-inherited member of a constructed type is obtained by substituting the type argument of the member declaration for the corresponding type argument of the constructed 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}{...}
}
Constructed type gen<int[],icomparable<string>> is like a member of the following.
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 the type declaration and is not a simple text-based substitution. The type of member a in the generic class declaration Gen is the "two-dimensional array of T" so the type of member A in the previously instantiated type is "two-dimensional array of one-dimensional array of int" 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 recursive applications of the current rule. Each of the inherited members is then converted by replacing each type parameter in the member declaration with the corresponding type argument for 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 d<int> member of the constructed type, public int G (string s), was obtained by substituting the type argument int of type parameter T. D<int> also has an inherited member that comes from class declaration B. This inherited member is determined to determine,b<t[]> members by first determining the members of the constructed type b<t[]> by replacing u with t[], generating public t[] F (long index). The type argument int then replaces the type parameter T, resulting in an inherited member public int[] F (long index).
Accessibility of 20.5.5 constructed types
When the constructed type C<t1,..., all parts of the tn> c,t1,..., TN is accessible, it is accessible. For example, if the generic type name C is public and all type parameters T1,..., tn is public, then the accessibility of the constructed type is 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, the accessibility of the constructed type is limited to that class, as well as subclasses within this assembly.
20.5.6 Conversion
The constructed type follows the same rule (§6) as the non-generic type. When these rules are applied, the base class and interface of the constructed type must be determined in the manner described in §20.5.3.
Except for those described in §6, there is no special conversion between the 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>, whether implicit or explicit, 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 obvious that you can store a value of type a into this list. This will destroy the invariance of the value of type B for each object in the list<b> type, or an unexpected error occurs when assigning a value on the collection class.
The behavior of the conversion and Run-time type checking are illustrated 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 collection
Collection C2 = Listb; Ok,list<b> is a collection
list<a> A1 = Listb; Error, no implicit conversions
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 the value of a type T can be null. The system.nullable<t> type is useful in many situations, such as indicating a nullable column for 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 the system.nullable<t>. In other words, you can write this
Nullable<int> x = null;
Nullable<string> y = null;
The same as the following.
nullable<int> x = nullable<int>.default;
Nullable<string> y = nullable<string>.default;
20.5.8 Use alias directives
You can use aliases to name a closed 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 generic type
Using X = N1. A.B; Error, cannot name 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, Attribute cannot be used as base class
Class list<t>
{
[A (typeof (T))] T T; Error, open type in attribute
}
Class X
{
[A (typeof (List<int>))] int x; OK, enclosing constructed type
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