Type four
20.6.5 Syntax Ambiguity
Simple-name and Member Access (Member-Access) in §20.9.3 and §20.9.4 are prone to syntax for expressions. For example, statement
F (g (7));
Can be interpreted as two parameters
[1]
. Similarly, it can also be interpreted as a call to F with a parameter, which is a call to the generic method G with two types of real parameters and a formal parameter.
If the expression can be parsed into two different effective methods, ">" can be parsed as all or part of the operator, or as a type of real parametery list, then ">" after ">" will be Be checked. If it is one of the following:
{}]>:;,.?
Then ">" is parsed as a list of real parameters. Otherwise, ">" is parsed as an operator.
20.6.6 Improvement Ways Method
The instance of the commission can be created by reference to a declaration of a generic method. Entrusted expression of exact compilation, including the commissioned creation of the reference generic method, which is described in §20.9.6.
When a generic method is called by delegate, the type of the type used will be determined when the entrusted instantiation. Types can be explicitly given by the type real parameter list, or by the type inference (20.6.4). If the type is used, the parameter type of the delegate will be used as the real parameter type of the inferior processing process. The return type of the delegate is not used. The following example shows a method for providing type-in-arguments for a commissioned instantiated expression.
Delegate Int D (String S, INT I)
Delegate Int E ();
Class X
{
Public Static T f
Public Static T g
Static void main ()
{
D D1 = New d (f
D d2 = new d (f); // ok, int is inferred as type
E E1 = New E (g
E E2 = new e (g); / / error, cannot be inferred from return type
}
}
In the previous example, the non-floating commission type is instantiated using generic methods. You can also create an instance of a constructor type using a generic method. In all situations, when the delegate instance is created, the type arguments are given or can be inferred, but when the delegate is called, the type real parameter list (§15.3) can be provided.
20.6.7 Non-floating properties, events, indexers or operators
Attributes, events, indexers, and operators They can have no types of arguments (although they can appear in generic classes and can be used in a closed class). If a similar properties is needed, it is replaced by you must use a generic method.
20.7 constraint
Pan type and method declaration can be optionally specified type parameter constraints, which can be done by confining the statement in the statement.
Type-parameter-constraints-clauses (Type Parameter Binding Schemrate :)
TYPE-Parameter-Constraints-Clause (Type Parameter Binding Fractor)
TYPE-Parameter-Constraints-Clauses Type-Parameter-Constraints-Clause (Type Parameter Constraint Foundation Type Parameter Binding Foundation)
Type-parameter-constraints-clause: (Type Parameter):) Where type-parameter: Type-Parameter-Constraints (Where type parameters: Type parameter constraint)
Type-parameter-constraints: (Type Parameter Constraint :)
Class-constraint (class constraint)
Interface-constraints (interface constraint)
Constructor-constraint (constructor constraint)
Class-constraint, interface-constraints (class constraint, interface constraint)
Class-constraint, constructor-constraint (class constraint, constructor constraint)
Interface-Constraints, Constructor-Constraint (Interface constraint, constructor constraint)
Class-constraint, interface-constraints, constructor-constraint (class constraint, interface constraint, constructor constraint)
Class-constraint: (class constraint :)
Class-type (class type)
Interface-constraint: (Interface constraint :)
Interface-constraint (interface constraint)
Interface-Constraints, Interface-Constraints (interface constraint, interface constraint)
Interface-constraints: (Interface constraint :)
Interface-Type (interface type)
Constructor-constraint: (Constructor Constraint :)
New ()
Each type Parameter Binding statement is followed by the name of the type parameters, followed by the key list of colon and type parameters. There is only one WHERE statement for each type parameter, but the where statement can be listed in any order. Similar to the GET and SET flags in the properties accessor, where statement is not a keyword.
A list of constraints given in the WHERE statement can be included in this order: a single class constraint, one or more interfaces and constructor constraints new ().
If the constraint is a class type or interface type, this type specifies the minimum "base type" of each type of type parameters that must be supported. Whenever a constructed type or generic method is used, the constraint of the type of arguments is checked for the type of arguments. The type of type provided must derive or implement all the constraints for that type parameters.
The type specified as a class constraint must follow the rules below.
This type must be a class type. This type must be sealed. This type cannot be the following type: System.Array, System.DeleGate, System.enum, or System.ValeType type. This type cannot be Object. Since all types are derived from Object, if this constraint will not work if it is allowed. At most, constraints for given type parameters can be a class type.
The type specified as an interface constraint must satisfy the following rules.
This type must be an interface type. The same type in a given WHERE statement cannot be specified multiple times. In many cases, constraints may contain any type of associated type or method declared as part of the constructor, and can include a declared type, but constraints cannot be a single type parameter.
Any class or interface type, as a type of parameter constraint, as a generic type or a declared method, must be at least accessible (10.5.4).
If a WHERE statement of a type parameter includes a new () form of constructor constraints, it is possible to use the New operator to create this type (§20.8.2) instance. Any type of type of argument for type parameters for constraints with a constructor must have a constructor (detailed situation to see 20.7).
Below is an example of possible constraints
Interface iPrintable
{
Void print ();
}
Interface IComparable
{
Int Compareto (T Value);
}
Interface IKeyProvider
{
T getKey ();
}
Class Printer
Class sortedlist
Class Dictionary
WHERE K: IComparable
Where: V: iPrintable, IKEYPROVIDER
{
...
}
The following example is an error because it tries to use a type parameter directly as a constraint.
Class Extend
The value of the type of parameter type of constraint can be used to access instance members of the constraint implied. In an example
Interface iPrintable
{
Void print ();
}
Class Printer
{
Void Printone (T x)
{
x.pint ();
}
}
The iPrintable method can be called directly on X because the T is constrained always implements iprintable.
20.7.1 Follow the constraint
Whenever constructed type or reference generic method, the type of types provided will be inspected for the declaration in generic type, or type parameter constraint in the method. For each WHERE statement, the type of type parameters corresponding to naming, the real parameter A will be checked as follows.
If the constraint is a class type or interface type, let C represent the constraint of the type of arguments, which will replace any type parameters that appear in the constraint. In order to follow constraints, type A must be in the following way, do not convert to type C:
-
Same conversion (6.1.1)
-
Implicit reference conversion (§6.1.4)
-
Packing conversion (6.1.5)
-
Implicit conversion from type parameters a to c (§20.7.4).
If the constraint is new (), the type of real parameters ca cannot be Abstract and must have a public unfolded constructor. If one of the following is true, this will be satisfied.
-
A is a value type (as described in §4.1.2, all value types have a public default constructor).
-
A is a non-Abstract class, and A contains a unparalleled constructor.
-
A is a non-Abstract class, and there is a default constructor (§ 10.10.4).
If one or more types of parameters are constrained by a given type, the compile error will occur.
Because the type parameters are not inherited, the same constraint will never be inherited. In the following example, D must specify constraints on its type parameter t to meet the constraints applied by the base class B
Class D
Class E > {...}
20.7.2 Members on the type parameters
In the type given by the type parameter T, the result of the member lookup depends on the constraint specified (if any) specified (if any). If t is not constrained or only new () constraints, the member looks on T, like a member lookup on the Object, returns a set of the same members. Otherwise, the first phase of the members will consider all members of each type of Type of T, the result will be merged, and then the hidden members will be deleted from the merges.
Before the generics appear, member lookup always returns a member of the unique statement in the class, or a member of a group that is the only statement in the interface, or the object type. Some changes have made some changes on the member lookup on the type parameters. When a type parameter has a class constraint and one or more interface constraints, member lookups can return a member, and these members have some declarations in the class, and some are declared in the interface. The following additional rules have been processed.
In the member lookup process (20.9.2), members declared in classes other than Object hide the members declared in the interface. During the reload decision decision process of the method and the index, if any available members are declared in a class different from the Object, all members declared in the interface will be removed from the considered Members collection.
These rules are only valid when binding a class constraint and interface constraints to the type parameters. Popular statement is that members defined in a class constraint are always preferred for members of the interface constraint.
20.7.3 Type parameters and packing
When a structural type rewriting inherits the virtual method in which system.object (equals, gethashcode or toString), the virtual method will not cause the virtual method through the instance of the structural type. This is true even if the structure is used as a type parameter, and the case occurs through the instance of the type parameter type. E.g
Using system;
Struct Counter
{
Int value;
Public override string toString ()
{
Value ;
Return value.toString ();
}
}
Class Program
{
Static void test
{
T x = new t ();
Console.writeline (x.toString ());
Console.writeline (x.toString ());
Console.writeline (x.toString ());
}
Static void main ()
{
Test
}
}
The output of the program is as follows
1
2
3
Although it is recommended not to let Tostring bring additional effects (Side Effect)
[2]
However, this example shows that the call for three X.toString () does not have a box.
When a member is accessed on a constraint, the packing will never happen. For example, assume that an interface ICOUNTER contains a method increment that can be used to modify a value. If ICOUNTER is used as a constraint, the implementation of the Increment method will be called through the reference to the variable called it, this variable is not a box copy. Using system;
Interface ICOUNTER
{
Void inccess ();
}
Struct Counter: ICOUNTER
{
Int value;
Public override string toString ()
{
Return value.toString ();
}
Void iCounter.Increment () {
Value ;
}
}
Class Program
{
Static void test
T x = new t ();
Console.writeline (x);
X.increment (); // Modify x`
Console.writeline (x);
(ICounter) .increment (); // Modify X's packing copy
Console.writeline (x);
}
Static void main ()
{
Test
}
}
The value of the first call for the variable X modified its value. This is not equivalent to the second call increment. The second modified is the copy after the X-box, so the output of the program is as follows.
20.7.4 Conversion of type parameters
The conversion allowed on the type parameter T depends on the constraint specified for T. All constrained or non-constrained type parameters can have the following conversion.
Implicit Same Conversion from T to T. Implicit conversion from T to Object. At runtime, if T is a value type, this will be made through a packing conversion. Otherwise, it will be converted as an implicit reference. Implicit conversion from Object to T. At runtime, if T is a value type, this will be performed by a unpacking manner. Otherwise it will be converted as an explicit reference. Explicit conversion from T to any interface type. At runtime, if T is a value type, this will be done by a packing conversion. Otherwise, it will be made through an explicit reference conversion. Implicit conversion from any interface type to T. At runtime, if T is a value type, this will be performed by a unpacking manner. Otherwise, it will be made as an explicit reference conversion.
If the type parameter T specifies an interface I as a constraint, there will be the following additional conversion.
The implicit conversion from T to I and the conversion of any base interface type from T to i. At runtime, if t is a value type, this will be made as a packing conversion. Otherwise, it will be made as an implicit reference conversion.
If the type of parameter T specifies the type C as a constraint, there will be the following additional conversion:
The implicit reference conversion from T to C, from T to any Class derived from the class, and from t to any interface from it. Explicit reference conversion from C to T, from C from Class Class [3] to T, and any interface to T
If there is an implicit user-defined conversion from C to A, the conversion from the implicit user of T to A. If there is an explicit user-defined transition from A to C, a transition from the explicit user of A to T. Implicit reference conversion from NULL type to T
An array Type T with an element type has the mutual conversion between Object and System.Array (6.1.4, §6.2.3). If T has the type type specified as a constraint, there will be the following additional rules.
From an array type AT with element type T to an implicit reference conversion of an array type Au with element type u, and if the following is true, there will be explicitly referenced from Au to AT: -
AT and AU have the same number of dimensions.
-
U is one of these: C, C from the type of derived type, the interface implemented by C, as the base reference specified by the constraint on T, the base reference specified.
Previous rules do not allow direct implicit conversions from non-constraint type parameters to non-interface types, which may be a bit strange. The reason is to prevent confusion and make this conversion more clearly. For example, consider the following statement.
Class x
{
Public static long f (t t) {
Return (long) t; // ok, allowed conversion
}
}
If t-to int explicit conversion is allowed, you may easily use x
Class x
{
Public Static Long F (t t)
{
Return (Object) T; // OK; Allow conversion
}
}
[1]
In this case, ">" is interpreted as larger than the operator.
[2]
When rewriting toString in the program, it is generally not recommended to add this similar calculation logic because it is not easy to control, increasing the complexity of the debugger.
[3]
C base class or the base class of its base class, etc.