This article is a Microsoft's technical article for translation. For reference for learning C #, please do not use for commercial purposes. http://msdn.microsoft.com/vcsharp/team/language/default.aspx
19.c # 2.0 Introduction
C # 2.0 Introduces several language extensions, which are generic, anonymous methods, iterators, and incomplete types (Partial Type).
Generics allows classes, structures, interfaces, commissions, and methods to be parameterized by the type of data they store and manipulated. The generic is very useful because they provide stronger compile time type checks, reducing explicit conversions between data types, as well as packing operations and runtime types.
An anonymous method allows code blocks to sneak into places where the expected entrusted value is in line. The anonymous method is similar to the lambda function in the LISP programming language. C # 2.0 supports the creation of "Closures", where the anonymous method can access the relevant local variables and parameters.
The iterator is a method of incrementing calculation and generating values. The iterator makes the type specifies how the Foreach statement iterates all the elements of it, it is easy.
Incomplete types allow class, structural, and interfaces to be split into multiple parts stored in different source files, which is more beneficial to development and maintenance. In addition, the incomplete type allows some types of machines to be separated from parts that are written in the user, so it is easy to increase the code generated by the tool.
This chapter will introduce these new features. After the introduction, the next four chapters provide the complete technical specifications for these features.
The language extension of C # 2.0 is mainly designed to ensure maximum compatibility between existing code. For example, although C # 2.0 gives the words for WHERE, YIELD and Partial, these words can still be used as identifiers. In fact, C # 2.0 does not add any keywords that may conflict with identifiers in existing code.
19.1 generics
Generics allows classes, structures, interfaces, commissions, and methods to be parameterized by the type of data they store and manipulated. C # generics is familiar for using Eiffel or ADA's generic users, or for users of C templates; but they will not have to endure the many complexities of the latter.
19.1.1 Why use a generic
If there is no generic, the data structure of the general purpose can use the Object type to store any type of data. For example, the following Stack class stores data in an Object array, and its two methods, PUSH, and POP use Object to receive and return data.
Public Class Stack
{
Object [] items;
INT country;
Public void push (Object item) {...}
Public Object Pop () {...}
}
Although the type Object can make the Stack class more flexible, do not have a shortcomings. For example, you can press a value, such as an instance of Customer, insert (Push) stack. However, when you retrieve a value, the result of the POP method must be explicitly converted to the appropriate type, checking the code for a runtime type, and is very annoying.
Stack stack = new stack ();
Stack.push (New Customer ());
Customer C = (Customer) stack.pop ();
If a value of a value type, for example, an int is passed to the Push method, it will be automatically contained. When this INT is obtained later, it must be removed using an explicit forced conversion.
Stack stack = new stack ();
STACK.PUSH (3);
INT i = (int) stack.pop ();
This packing and unloading operation add performance overhead because they involve dynamic memory allocation and runtime type checks. The bigger problem with the Stack class is that it cannot force the data types on the stack. In fact, the Customer instance can be pressed into the stack, and may be forced to convert to the wrong type when retrieving it.
Stack stack = new stack ();
Stack.push (New Customer ());
STRING S = (String) stack.pop ();
Although the previous code is an inappropriate usage of the Stack class, this code is technically correct, and it will not report errors when compiling. The problem will come out until the code is executed, and an InvalidCastException exception will be thrown at this point.
If the Stack class has the ability to specify its element, it is clear that it can be beneficial from this capability. This will become possible using a generic.
19.1.2 Creating and using generics
The generics provides tools for creating types with type parameters. The following example declares a generic STACK class with type parameter T. Type parameters are specified in the <"and"> "dividing character after class name. There is no other conversion between Object and other types, and instances of Stack
Public Class Stack
{
T [] items;
INT country;
Public void push (t item) {...}
Public T Pop () {...}
}
When the generic class Stack
Stack
STACK.PUSH (3);
INT x = stack.pop ();
Stack
The generic type provides a strong type, such as, for example, embraced an int to Customer object stack will have an error. It seems that STACK
For the following example, the compiler will report an error in the last two lines.
Stack
Stack.push (New Customer ());
Customer c = stack.pop ();
Stack.push (3); // type does not match errors
INT x = stack.pop (); // type does not match errors
The generic type declaration can have any number of types of parameters. Previous Stack
{
Public Void Add (K Key, V Value) {...}
Public v this [k Key] {...}
}
When Dictionary
Dictionary
Dict.Add ("Peter", New Customer ());
Custeomer C = DICT ["peter"];
19.1.3 Instantization of generic types
Similar to the non-float type, the compiled generic type is also indicated by the intermediate language [Intermediate Language (IL)] instruction and metadata. The generic type of generic type is of course encoding the existence and use of type parameters.
When the application creates an instance of a generic type, for example, Stack
.NET public language runtime use value type creates a specific copy of a local code for each generic type instance, but for all reference types, it will share a single copy of local code (because of the local code level, reference It is just a pointer with the same representation).
19.1.4 constraint
Generally speaking, generic classes are not limited to storage values based on type parameters. Pancases often call methods on objects of a given type parameter. For example, the Add method in the Dictionary
Public Class Dictionary
{
Public Void Add (K Key, V Value)
{
...
IF (Key.Compareto (x) <0) {...} // error, no Compareto method
...
}
}
Because the type parameters specified for K may be any type, it is assumed that the only member of the Key parameter is those that are declared object type, for example, equals, gethashcode and torstring; therefore, when compiling in the previous example error. Of course, you can force the Key parameter to a type containing the CompareTo method. For example, the Key parameter may be forced to convert to the iComparable interface.
Public Class Dictionary
{
Public Void Add (K Key, V Value)
{
...
IF ((iComparable) key) .compareto (x) <0) {...}
...
}
}
Although this solution is valid, it needs to perform dynamic type check at runtime, which has also increased overhead. Worse, it will post the error report to run, if the key (key) does not implement the ICOMPARABLE interface will throw an InvalidCastException exception.
In order to provide a stronger compile time type check, and reduce type forced conversion, C # allows each type of parameters to provide an optional list of constraints. Type parameter constraints specify a need for a type that must be fulfilled, and its purpose is to be used as an argument for type parameters. Constraints WHERE declarations, followed by the name of the type parameters, followed by a list of class or interface type, and optional constructor constraints new ().
Public Class Dictionary
{
Public Void Add (K Key, V Value)
{
...
IF (Key.Compareto (x) <0) {...}
...
}
}
Given this statement, the compiler will ensure that any type of collections of K are the type of ICOMPARABLE interface.
Also, it is no longer necessary to explicitly enforce the key parameter before calling the CompareTo method. All members of the type given for type parameters as a constraint are directly effective for values for type parameter types.
For a given type parameter, you can specify any number of interfaces as constraints, but only one class. The type parameters of each constraint have a separate WHERE statement. In the following example, the type parameter k has two interface constraints, and the type parameter E has a class constraint and a constructor constraint.
Public Class EntityTable
WHERE K: IComparable
WHERE E: E: E: E: E: E: E: E: E: E: E: E: E: E: E: E:
{
Public Void Add (K Key, E Entity)
{
...
IF (Key.Compareto (x) <0) {...}
...
}
}
In the previous example, the function constraints NEW () ensures that the type e used as the type of type parameters has a public, no parameter constructor, and it allows the generic class to create this type of instance using new E ().
Type parameter constraints should be very careful. Although they provide stronger compile time type checking, in some cases enhanced performance, they also limit possible usage of generic types. For example, generic class List