Return Item1;
}
Return Item2;
}
}
This code is invalid in the CLR model. The error generated by the C # compiler is as follows:
Invalid.cs (4,11): Error CS0019: Operator '<' Cannot Be Applied To
Operands of type 't' and 't'
At the same time, in addition to subtle grammatical differences, the substantially the same code is permitted in the C template. Why is there such a limit on the model? The reason is: In C #, the "<" operator can only be used for a specific type. However, the type parameter t in the previous code snippet can be extended to any CLR type at runtime. The front code example is not considered invalid at runtime, but is considered invalid when compiling.
In addition to operators, more manageable types are used (for example, method calls) also applied the same limit. The following to the MIN method is also an invalid range code:
Class genericmath {
Public T MIN (t item1, t item2) {
IF (item1.compareto (item2) <0) {
Return Item1;
}
Return Item2;
}
}
The reason why this code is invalid is the same as the previous example. Although many of the types in the class library implements the CompareTo method, and this method is also easy to implement by your custom type, but this method is not guaranteed to apply to any possible type of parameters that can be used as T. But you can also see that the modest code is not completely prohibited. In FIG. 1, the GetHashCode method is called in two parameterized variables, and in FIG. 2, the Node is called to TOSTRING method in its parameterized m_data field. Why allow GetHashCode and TOSTRING, not compare? The reason is that getHashCode and Tositring are defined in the System.Object type, while each possible CLR type is also derived from this type. This means that each possible extension of type T enables TOSTRING and GETHASHCODE member functions.
If the model can be used for any class other than the collections, the model code needs to be able to call a method other than the method defined by System.Object. However, remember that the model code is only valid when any possible constructor used for the model. There is a way to solve these two seemingly contradictory requirements, that is, the function called constraint in the CLR model.
You should know that constraints are an optional component defined by a model or method. In the type of a type parameter that can be used as a variable, a model can define any number of constraints, while each constraint can apply any one. By limiting the type of code that can be used in the regular structure, it can relax the restriction of the code of the restricted type parameter (see Figure 3).
Because constraints are applied to the type parameter T, MIN and Max are valid on its entry to COMPARETO. In the third line of Figure 3, you can see that it introduces the WHERE clause shown below:
Back to top
Where t: iComparable
This constraint indicates that any structure of the MIN method must provide a type variable to the parameter T of the type of the IComparable interface. This constraint limits the possible specification of MIN , but improves the flexibility of the code in the method, such as now you can call COMPARETO on the variable of type T.
The constraint is possible to make the paradition algorithm possible by allowing the model code to call any method on the extended type. Although constraints require additional syntax to define a model code, the constraint does not change the syntax of the reference code. The only difference between reference code is that type variables must comply with the constraints of the model. For example, the following quotation code for MAX is effective:
Genericmath.min (5, 10);
This is because 5 and 10 are integers, and the INT32 type implements the IComparable interface. However, trying to implement the following Max structure generate compiler error:
Genericmath.min (New Object (), New Object ());
Below is an error generated by the compiler:
MinMax.cs (32, 7): Error CS0309: The Type 'Object' Must Be Convertible
To 'System.icomparable' in Order to Use it is parameter 't' in the
Generic Type or Method 'Genericmath.min (T, T)'
For T, System.Object is an invalid type variable because it does not implement the iComparable interface that implements the constraints of T. When the type variable is incompatible with the type parameters on the model code, the constraint may cause the compiler to generate a descriptive error as shown in the previous example. Currently, the model supports three types of constraints: interface constraints, base classes constraints, and constructor constraints. Interface constraints specify an interface that all type variables of this parameter must be compatible with this interface. Any number of interface constraints can be applied to a given type parameter.
The base class constraint is similar to the interface constraint, but each type parameter can only contain one base class constraint. If you don't specify constraints for the type parameter, the implicit base class constraint for Object is applied.
Constructor constraints The type variable of the type of the public default constructor is restrained, so that the model code can create an instance of the type specified by the type parameter. Currently, constructor constraints only support the default or no parameter constructor.
The WHERE clause is used to define constraints or constraints for a given type parameter. Each WHERE clause is applied only to a type parameter. Van Dialect or method definition can be without WHERE clauses, or the WHERE clause is as much as the type parameters. A given WHERE clause can contain a constraint or a list of constraints separated by a comma. Figure 4 shows various grammar for the model application application constraints.
The basic rules of the model (all possible instantiation of the model are effective, or the model itself is invalid) There are other interesting side effects. The first is forced type conversion. In the norm code, the variable of the type parameter type may only be mandatory with each other's base class constraint type or base class constraint type. This means that if the type parameter T is not constrained, it can only be mutually enforced with the Object reference. However, if the T constraint is a type further derived (eg, fileStream), the model definition may include T and the FileStream and the mutual forced conversion between all the base classes (until Object) of the FILESTREAM. The code in Figure 5 shows such a forced conversion rule in the action.
In this example, T is not constrained and is considered unbound. It has an implicit baseline constraint for Object. The mutual mandatory conversion between T and the Object class and the mutual forced conversion between the interface type are valid. However, the compiler does not allow unbound T forced to convert to other types (such as INT32). The mandatory conversion rules for the norm are also suitable for conversion, so that the forced conversion syntax is not allowed to perform type conversion (such as converting from INT32 to INT64); the model does not support similar conversion.
Here is another interesting thing. Consider the following code:
Void foo () {
T x = null; // compiler error WHEN T IS unbounded
•••••
Although it is often used in this air value, there may be a problem. What happens if the T is expanded as a value type? It is meaningless to assign a value variable. Fortunately, the C # compiler provides special syntax to ensure the correct result, without the runtime type of tube T:
Void foo () {t x = t.default; // ok for any t}
The expression on the right side is called the default expression. If T is extended to a reference type, T. DEFAULT will resolve to NULL. If the T is expanded into a value type, the T. DEFAULT is a value of all bits to all bits.
If T is not binding, the parameterized variable T is not allowed to assign a null value, so someone may think that the following statement is also invalid, but the fact is not this:
Void foo (t x) {
IF (x == null) {// ok •••
}
}
What happens if NULL is allowed here, what happens when T is expanded as a value type? If t is a value type, the Boolean expression in the previous example will force to false. Unlike an empty value, any expansion of T is meaningful for any expansion of T.
For any possible instantiation, it is true that the model code is effectively valid when compiling. However, I found that the additional structure around the CLR in C has a significant role than the template in C . In short, the infrastructure around the constraint and its surroundings is one of my favorite aspects in the CLR model.
Back to top
Fan interface and commission
Van type, structure and method are the main functions of the CLR model. Valence interfaces and entrustments are the functions that truly support. If the model interface is used alone, it is limited. However, when used with a model class, a structure or method, a model interface (and delegate) will have an important role.
The genermath.min and genericmath.max method in Figure 3 are compatible with the iComparable interface. This allows these methods to call Compato on the parameterized variable of the method. However, these methods implemented in Figure 3 have not fully utilized the advantages of the model. The reason is that if the interface uses one or more object parameters (for example, CompareTo's OBJ parameters), the non-flavor-type interface of the call value type can cause the box.
For GeneralMath.min in Figure 3, if the instantiation of the method is expanded to a value rather than a reference, each calling this method can cause parameters of the CompareTo method. At this time, the model interface can be used.
The code in Figure 6 reconstructs the genericMath method to confine T by a model interface ICOMPARABLE . Now, if MIN or Max uses the value type as the variable variable, the interface call to CompareTo is part of the interface structure, and its parameters are value types, and no packing.
Valence commission has the benefits of similar interfaces, but it is a method for ways and non-directional types.
Back to top
Model in the class library
In addition to achieving models in the CLR, Microsoft also plans to provide new paradigm libraries to serve as part of CLR versions of the CLR number "whidbey". When published in this column, the preview of the Whidbey CLR should be launched. (For more information, please refer to the 2003 September 2003 of this column.) The most conservative estimate will provide a list of implementations, dictionary, stacks, and queues. In addition, class libraries will also include supported interface types (such as ILIST , Icollection , IComparable ), which is an equivalent model of Simple interface included with Microsoft .NET Framework 1.0 and 1.1 class library. .
Finally, you will also find that the types in the entire class library will be parameterized with new and existing features. For example, the System.Array class will contain a model version of its BinarySearch and Sort methods that utilize paradigm interface iComparer , and iComparable . When writing this article, Microsoft® has not determined how much changes to existing class libraries so that the model support is included in the next runtime version.
Back to top
summary
The CLR model is a powerful application and library development feature. Whether you are using a model by using a collection class, or choose the entire application to apply a model, the model can make your code type safer and maintain, and efficient. In these two periods in this column, the model programming has brought me a lot of fun in the hosted code, and I also look forward to the product to be released. It is an exciting thing to see that the CLR adds an important feature such as a model. There may also be much more interest. Please continue to pay attention to our work. Please send Jason's questions and comments to dot-net@microsoft.com.
Jason Clark provides training and consulting for Microsoft and Wintelle, and he used to be developers of Windows NT and Windows 2000 Server team. He combined with people with a book of Programming Server-Side Applications for Microsoft Windows 2000 (Microsoft Press, 2000). You can contact Jason with JCLARK@wintellect.com.