C # 2.0 specification (i) Introduction

Source: Internet
Author: User
Tags anonymous constructor count data structures interface new features reference sort
19.c#2.0 Introduction
C#2.0 introduces several language extensions, the most important of which are generics, anonymous methods, iterators, and incomplete types (partial type).

Generics allow classes, structs, interfaces, delegates, and methods to be parameterized by the type of data they store and manipulate. Generics are useful because they provide stronger compile-time type checking, reduce explicit conversions between data types, and boxing and Run-time type checks.
Anonymous methods allow the code block to sneak inline into the desired delegate value. The anonymous method is similar to the lambda function in the Lisp programming language. C#2.0 supports the creation of "closures", where anonymous methods can access related local variables and parameters.
Iterators are methods that can increment and produce values. An iterator makes it easy to specify how a foreach statement iterates through all of its elements.
Incomplete types allow classes, structs, and interfaces to be split into parts stored in different source files, which is more conducive to development and maintenance. In addition, incomplete types allow the separation of some types of machine-generated parts from user-written parts, so it is easy to increase the code generated by the tool.


These new features are described in this chapter. After the introduction, the next four chapters provide a complete technical specification of these features.

C#2.0 's language extensions are designed primarily to ensure maximum compatibility with existing code. For example, although c#2.0 gives special meaning to the terms of where, yield, and partial in a particular context, these words can still be used as identifiers. In fact, C # 2.0 does not add any keywords that might conflict with identifiers in existing code.

19.1 generic type
Generics allow classes, structs, interfaces, delegates, and methods to be parameterized by the type of data they store and manipulate. C # Generics are familiar to users who use Eiffel or ADA generics, or to users of C + + templates, but they will not have to endure the complexity of the latter.





19.1.1 Why use Generics
Without generics, common purpose data structures can store any type of data using object type. 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 accordingly.

public class Stack

{

object[] items;

int count;

public void Push (item) {...}

public Object Pop () {...}

}

Although using type object can make the stack class more flexible, it is not without drawbacks. For example, you can push a stack of any type of value, such as a customer's instance. But when you retrieve a value, the result of the Pop method must be explicitly cast to the appropriate type, and it is annoying to write code for a run-time type check, and to have a negative performance impact.

Stack stack = new stack ();

Stack.push (New Customer ());

Customer C = (customer) stack. Pop ();

If the value of a value type, such as an int, is passed to the push method, it will be boxed automatically. When this int is obtained later, it must be unboxed with an explicit cast.

Stack stack = new stack ();

Stack.push (3);

int I = (int) stack. Pop ();

This boxing and unboxing operation increases the performance overhead because they involve the allocation of dynamic memory and Run-time type checking.

The bigger problem with the stack class is that it cannot force the kind of data that is placed on the stack. In fact, the customer instance can be pressed onto the stack and may be cast back to the wrong type when it is retrieved.

Stack stack = new stack ();

Stack.push (New Customer ());

string s = (string) stack. Pop ();





Although the previous code is an improper use of the stack class, this code is technically correct and does not report a compile-time error. The problem will not pop up until the code executes, and a InvalidCastException exception will be thrown at this point.

If the Stack class has the type capability to specify its elements, then it is clear that it benefits from this capability. Using generics, this will become possible.

19.1.2 creation and use of generics
Generics provide a tool for creating types that have type parameters (types parameter). The following example declares a generic stack class with type parameter T. Type parameters are specified in the "<" and ">" delimiters after the class name. There is no reciprocal conversion between object and other types the,stack<t> instance accepts the type when they are created, and stores that type of data without converting it. The type parameter T acts as a placeholder and specifies an actual type until it is used. Note that T is used as the element type of the internal items array, the type of the push method parameter, and the return value type of the Pop method.

public class Stack<t>

{

t[] items;

int count;

public void Push (T item) {...}

Public T Pop () {...}

}

When a generic class stack<t> is used, the actual type that T replaces is specified. In the following example, the int is given as the type parameter of T.

stack<int> stack = new stack<int> ();

Stack.push (3);

int x = stack. Pop ();

The stack<int> type is called a constructed type (constructed type). In the stack<int> type, each occurrence of T is replaced with a type parameter int. When an instance of stack<int> is created, the local storage of the items array is a int[] rather than a object[], which provides a higher storage efficiency than a non-generic stack. Similarly, the push and pop methods for stack<int> operations on an int value will cause a compile-time error to be pressed into other types of values into the stack, and no conversion back to their original type is required when the value is retrieved.

Generics provide a strong type, meaning such as pressing an int to the customer object stack will cause an error. It is as if stack<int> is restricted to operate on an int value, and the same stack<customer> is limited to the Customer object.

For the following example, the compiler will report an error in the last two lines.





stack<customer> stack = new stack<customer> ();

Stack.push (New Customer ());

Customer C = Stack. Pop ();

Stack. Push (3); Type mismatch error

int x = stack. Pop (); Type mismatch error

A generic type declaration can have any number of type parameters. The previous stack<t> example had only one type parameter, but a generic dictionary class might have two type parameters, one for key (key), and the other for the type of values (value).

public class dictionary<k, v>

{

public void Add (K key, V value) {...}

Public V this[k key]{...}

}

When Dictionary<k, v> is used, two types of parameters must be supplied.

dictionary<string, customer> dict = new dictionary<string, customer> ();

Dict.add ("Peter", New Customer ());

Custeomer C = dict["Perter"];

19.1.3 generic type instantiation
Similar to non-generic types, compiled generic types are represented by intermediate language [intermediate Language (IL)] directives and metadata. The representation of a generic type, of course, also encodes the existence and use of a type parameter.

When an application first creates an instance of a constructed generic type, for example, Stack<int>,. NET common Language runtime's Just-in-time compiler (JIT) converts the generic IL and metadata into local code in the process, and replaces the type parameter with the actual type. Subsequent references to that constructed generic type will use the same native code. The process of creating a particular constructed type from a generic type, called a generic type instantiation (generic type instantiation).

. NET common language runtime uses value types to create a specific copy of a local code for each generic type instance, but for all reference types it will share a single copy of that local code (because, at the local code level, the reference is just a pointer with the same representation).

19.1.4 constraints
Generally speaking, generic classes are not limited to storing values based on type parameters only. Generic classes can often invoke methods on objects of the type of a given type parameter. For example, Dictionary<k, the Add method in the V> class might need to compare key values using the CompareTo method.



public class dictionary<k, v>

{

public void Add (K key, V value)

{

...

if (Key.compareto (x) <0) {...} Error, no CompareTo method

...

}

}

Because the type parameter specified for k may be of any type, you can assume that the key parameter exists as the only member, that is, those declared as type object, such as Equals,gethashcode and ToString, so that a compile-time error occurs in the previous example. Of course, you can cast the key argument to a type that contains the CompareTo method. For example, the key parameter may be cast to the IComparable interface.

public class dictionary<k, v>

{

public void Add (K key, V value)

{

...

if ((IComparable) key). CompareTo (x) <0) {...}

...

}

}

Although this workaround works, it requires dynamic type checking at run time, which also increases overhead. Worse, it defers the error report to the runtime, and if the key does not implement the IComparable interface will throw a InvalidCastException exception.

To provide a stronger compile-time type check and reduce type casts, C # allows an optional list of constraints (constraint) for each type parameter. A type parameter constraint specifies a requirement that a type must perform to be used as an argument (argument) for a type parameter. The constraint uses the word where declaration, followed by the name of the type parameter, followed by a list of class or interface types, and an optional constructor constraint new ().

public class dictionary<k, v> where k:icomparable

{

public void Add (K key, V value)

{

...

if (Key.compareto (x) <0) {...}

...

}

}



Given this declaration, the compiler will ensure that any type of argument of K is the type that implements the IComparable interface.

Also, you no longer need to explicitly cast the key parameter before calling the CompareTo method. All members of a type given a type parameter as a constraint are directly valid for the value of the type parameter type.

For a given type parameter, you can specify any number of interfaces as constraints, but only one class. The type parameter for each constraint has 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<k, e>

where k:icomparable<k>,ipersisable

where e:entity, New ()

{

public void Add (K key, E entity)

{

...

if (Key.compareto (x) <0) {...}

...

}

}

In the previous example, the constructor constraint new () ensures that the type used as the type parameter for E has a public, parameterless constructor, and that it allows the generic class to create an instance of the type using new E ().

Type parameter constraints should be used with caution. Although they provide stronger compile-time type checking and, in some cases, enhanced performance, they also limit the possible use of generic types. For example, a generic class list<t> might constrain T to implement the IComparable interface, whereby its sort method can compare the size of an item. However, this makes it impossible for types that do not implement the IComparable interface to use LIST&LT;T&GT, even in these cases where the sort method is not invoked at all.


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.