Source: mircrosoft.net 2.0 beta1 sdk
Translation: Jim Xu Date:
2004-11-2
Generic is a new feature of C # language 2.0 and general language runtime (CLR). The generic introduction of the concept of type parameters is introduced for .NET framework. When the type parameters make the design classes and methods, it is not necessary to determine one or more specific parameters, and the specific parameters of which can be delayed in the customer code, implementation. This means using generic type parameters T, write a class MYLIST
table of Contents
Wan in C #. 1
I. Overview of generics. 2
Second, the advantages of generics. 5
Third, generic type parameters. 7
Fourth, the constraint of type parameters. 8
Five, generic class. 11
Sixth, generic interface. 13
Seven, generic method. 19
Eight, generic commission. 21
Nine, default keywords in generic code. 23
Ten, C templates and C # generics. 24
Eleven, the generics in runtime. 25
Twelve, generics in the basic class. 27
First, generic overview
Pan-type and generic methods and generic methods, type safety and high efficiency are not in the corresponding non-floating class and methods. Wide generics is widely used in the container and the container operation. The .NET Framework 2.0 class library provides a new namespace system.collections.Generic, which contains some new generic-based container classes. To find the sample code of the new generic container class, see generics in the underlying class library. Of course, you can also create our generic classes and methods to provide your own generalized program and design model, which is safe and efficient. The following sample code is an exemplary in a simple generic chain class class. (In most cases, it is recommended to use the List
l In the AddHead method, as the type of method parameters.
l In public method GetNext, as a type of return value in the DATA property of the nested Node.
l In nested classes, as the type of private member DATA.
Note that T is also effective to Node Node node. When using a specific class to implement MYLIST
Using system;
Using system.collections.Generic;
Public Class MyList
{
PRIVATE NODE Head;
// The Nested Type is Also Generic on T.
Private class node
{
PRIVATE NODE NEXT;
// t as private member data type:
Private t data;
// t used in non-generic constructor:
Public node (t t)
{
Next = NULL;
Data = T;
}
Public node next
{
Get {returniful
Set {next = value;}}
// t as return type of property:
Public T Data
{
Get {returntric;}
SET {data = value;}
}
}
Public mylist ()
{
HEAD = NULL;
}
// t as method parameter type:
Public void addhead (t t)
{
Node n = new node (t);
N.NEXT = HEAD;
HEAD = N;
}
Public IEnumerator
{
Node current = head;
While (current! = null)
{
Yield Return Current.data;
Current = Current.next;
}
}
}
The sample code below demonstrates how the customer code uses generic class MYLIST
Class Program
{
Static void
Main
(String [] ARGS)
{
// int is the Type Argument.
MYLIST
For (int x = 0; x <10; x )
List.addhead (x);
Foreach (int i in list)
{
Console.writeLine (i);
}
Console.WriteLine ("DONE");
}
}
Second, the advantages of generics
For earlier versions of general language runtime and C # language limitations, generics provide a solution. Previous types of generalization are achieved by the type of mutual conversion of the global base class system.Object. The ArrayList container class of the .NET Framework Baseline is an example of this limitation. ArrayList is a very convenient container class, which can store any reference types or value types without changes.
// The .NET Framework 1.1 Way of Creating a list
ArrayList List1 = new arraylist ();
List1.add (3);
List1.add (105);
// ...
ArrayList List2 = new arraylist ();
List2.add ("IT IS RAINING IN
Redmond
");
List2.add ("It is snowing in the mountains);
// ...
But this convenience is cost, which requires any one of the reference types or value types to join ArrayList to SYSTEM.OBJECT. If these elements are value type, they must be packaged when they are added to the list; when retrieving them, to remove it. Type conversion and packing, unpacking operations reduce performance; in the case of an iterate large capacitor, the impact of packing and unpacking may be significant.
Another limit is a lack of time-compiled type checking, when an arraylist converts any type to Object, it cannot be used to prevent customer code like this:
ArrayList List = New ArrayList ();
// okay.
List.add (3);
// Okay, But Did you real want to do this? List.add (. "IT IS RAINING IN
Redmond
");
INT T = 0;
// this causes an invalidcastexception to be returned.
Foreach (int x in list)
{
T = X;
}
Although this is completely legitimate, and sometimes intention to create a container containing different types of elements, putting the string and int variables in an ArrayList, almost in manufacturing errors, and this error will not be discovered when it is running.
In the C # language of version 1.0 and version 1.1, you can only avoid the danger of generalized code in the container class of the .NET Framework class by writing your own specific type of container. Of course, because such classes cannot be reused by other data types, they will lose the advantages of genericity, and you must rewrite the class for each type of store.
ARRAYLIST and other similar classes truly need a way to allow customer code to specify the specific data type required before instantification. This will not be required to convert the top type to Object, and the compiler can perform type check simultaneously. In other words, ArrayList needs a type of parameters. This is precisely provided. In the generic list
The .NET Framework 2.0 Way of Creating A List
List
// no boxing, no casting:
List1.add (3);
// Compile-Time error:
List1.add ("IT IS Raining in
Redmond
");
Compared to ArrayList, the only List
Third, generic type parameters
In the definition of generic type or generic method, the type parameter is a placeholder, usually a capital letter, such as T. When the customer code declaration, instantiate the variable of this type, replace the Type of the data specified by the customer code. Wynhat types, such as Mylist
MYLIST
MYLIST
MYLIST
In these MYLIST
To check an element in the table to determine if it is legal or if it can be compared to other elements, then the compiler must ensure that all types of parameters that may occur in the customer code must support the operations or methods of the required calls. This guarantee is obtained by applying one or more constraints by definition of generic classes. A constraint type is a base class constraint that notifies the compiler, only this type of object or object from this type, can be used as a type parameter. Once the compiler gets this guarantee, it allows this type of method to be called in the generic class. The context key WHERE is used to achieve constraints. The following sample code illustrates the application of the base class constraint to add functions to myList
Public Class Employee
{
Public Class Employee
{
PRIVATE STRING NAME;
Private int ID;
Public Employee (String S, INT i)
{
Name = s;
ID = i;
}
Public String Name
{
Get {return name;}
Set {name = value;}
}
Public Int ID
{
Get {return id;}
Set {id = value;}
}
}
}
Class MyList
{
// REST OF Class as Before.
Public T Findfirstoccurrence (String S)
{
T t = null;
RESET ();
While (Hasitems ())
{
IF (Current! = NULL)
{
// The constraint enables this:
IF (current.data.name == s)
{
T = Current.data;
Break;
}
Else
{
Current = Current.next;
}
} // end if
} // End while
Return T;
}
}
Constraints allow generic classes to use the EMPLOYEE.NAME attribute, because all elements of type T are an Employee object or an object inherited from EMPLOYEE.
The same type of parameters can apply multiple constraints. The constraint itself can be a generic class, as follows:
Class MyList
{...}
The following table lists five types of constraints:
constraint
description
Where t: struct
Type parameters must be a value type.
Where t: Class
Type parameters must be type.
Where t: new ()
Type parameters must have a public, no parametric constructor. When used in other constraints, the New () constraint must be placed in the end.
WHERE T:
Type parameters must be the specified base type or derived from the specified base type.
Where t:
Type parameters must be the specified interface or the implementation of the specified interface. You can specify a plurality of interface constraints. Interface constraints can also be generic.
The constraint of type parameters increases the number of operations and methods that can be called. These operations and methods are supported by the type of constraint and the type in its derived level. Thus, when designing a generic class or method, if the generic member executes any assignment, or the method does not in call System.Object, it is necessary to use constraints on the type parameters. General usage of unrestricted type parameters
There is no constraint type parameter, such as T in public class MyClass
l Can't use operators! = and ==, because the specific type parameters cannot be guaranteed to support these operators.
l They can be converted to System.Object, or explicitly convert to any interface type.
l can be compared to NULL. If a non-restriction type parameter is compared with NULL, when this type of parameter is a value type, the comparison result is always false.
None type constraint
When the constraint is a generic type parameter, it is called Naked Type Constraints. When a type of type parameter is a type of parameter, it is useful to constrain its parameters to the type parameters of its class. As shown in the following example:
Class List
{
// ...
Void Add (list items) where u: t {...}
}
In the above example, t in the context of the Add method is a non-type constraint; the t in the context of the List class is a unlimited type parameter.
None type constraints can also be used in the definition of generic classes. Note that there is no type of constraint to declare in sharp brackets with other types of parameters:
// Naked Type Constraint
Public Class Myclass
Since the compiler only believes that there is no type of constraint inherits from System.Object, the use of generic classes with non-type constraints is very limited. When you want to force two types of parameters to have inheritance relationships, there is no type of constraints for generic classes.
Five, generic class
The generic classes encapsulates the operations that are not for any particular data type. Generic classes are often used in containers, such as linkers, hash tables, stacks, queues, trees, and so on. The operations in these classes, such as adding, deleting elements, regardless of the type of data stored, performs almost the same operation.
For most cases, it is recommended to use the container classes provided in the .NET Framework 2.0 class. For more information on using these classes, see generics in the underlying class library.
Typically, a generic class is created from an existing concrete class and a type changed to a type parameter each time until the best balance of general and usability. When you create your own generic class, you need to focus on things:
l What types of types should be generic as type parameters. The general rules are, the more the types represented by parameters, the greater the flexibility and reuse of the code. Excessive generalization can cause code to be understood by other developers.
l If there is constraint, then the type parameters need to be constrained. A good habit is to use the largest constraint as much as possible while ensuring that all types that need to be processed can be processed. For example, if you know that your generic class is intended to use the reference type, then apply this class's constraint. This prevents unintentional use value, while using an AS operator to T, and check the air reference.
l Placing generics in the base class or in subclasses. The generic class can be a base class. This should also be considered in the design of the same non-flora. Inheritance rules for generic base classes.
l Whether to implement one or more generic interfaces. For example, to design a class that creates an element in a generic-based container, you may need to implement an interface similar to ICOMPARABLE
Rules for type parameters and constraints have some potential impact on generic behavior (Behavior), especially for inheritance and member accessibility. It is important to understand some terms before explaining this problem. For a generic class Node
// Concrete Type
Class Node
// Closed Constructed Type
Class Node
// Open Constructed Type
Class Node
The non-floating specific classes can inherit self-enclosed construction base, but cannot inherit from open construction base classes. This is because the customer code cannot provide the type parameters required by the base class.
// No error.
Class Node: BaseNode
// generates an error.
Class Node: BaseNode
The generic specific class can inherit the type of self-opening structure. In addition to the type parameters shared with the subclass, the type must be specified for all type parameters, as shown in the following code:
// generates an error.
Class Node
// okay.
Class Node
Inherit the generic class of the open structure type, must be specified:
Generic Classes That Inherit from Open Constructed Types Must Specify Must Specify Constraints That Are A SuperSet of, or Imply, The Constraints on The Base Type:
Class NodeItem
Class MyNodeItem
The generic type can use multiple types of parameters and constraints, as follows:
Class Keytype
Class SuperkeyType
Open structure and enclosed construct Types can be used as parameters:
Void SWAP
Void swap (list
Six, generic interface
Whether it is a generic container, it is also useful to define the extension of the generic class in the container. Combining generic interfaces with generic classes is better usage, such as ICOMPARABLE
This allows the Bubblesort method in sortedlist
Using system;
Using system.collections.Generic;
// Type Parameter T IN Angle Brackets.
Public Class MyList
{
Protected node head;
protected node current = null;
// Nested Type is Also Generic on T
Protected Class Node
{
Public node next;
// t as private member datattype.
Private t data;
// t used in non-generic constructor.
Public node (t t)
{
Next = NULL;
Data = T;
}
Public node next
{
Get {returniful
Set {next = value;}
}
// t as return type of profment.
Public T Data
{
Get {returntric;}
SET {data = value;}
}
}
Public mylist ()
{
HEAD = NULL;
}
// t as method parameter type.
Public void addhead (t t)
{
Node n = new node (t);
N.NEXT = HEAD;
HEAD = N;
}
// Implement IEnumerator
// ortho orthot there. Note That In C # 2.0
// you are not required and import current and
// GetNext. The compiler does That for you.
Public IEnumerator
{
Node current = head;
While (current! = null)
{
Yield Return Current.data;
Current = Current.next;
}
}
}
Public Class SortedList
{
// a Simple, Unoptimized Sort Algorithm That // Orders List Elements from Lowest to Highest:
Public void bubblesort ()
{
IF (null == head || null == head.next)
Return;
BOOL swapped;
DO
{
Node previous = null;
Node current = head;
Swapped = false;
While (current.next! = null)
{
// Because We need to call this method, The sortedlist
// Class Is Constrained On IEnumerable
IF (current.data.compareto (current.next.data)> 0)
{
Node TMP = Current.next;
Current.next = current.next.next;
TMP.NEXT = CURRENT;
IF (previous == NULL)
{
HEAD = TMP;
}
Else
{
Previous.Next = TMP;
}
Previous = TMP;
Swapped = true;
}
Else
{
Previous = CURRENT;
Current = Current.next;
}
} // End while
WHILE (SWAPPED);
}
}
// a Simple Class That IMPLEments ICOMPARABLE
// using itself as the type argument. this is a
// Common Design Pattern in Objects That Are
// stored in Generic Lists.
Public Class Person: iComparable
{
String name;
Int agec;
Public Person (String S, INT I)
{
Name = s;
AGE = I;
}
// this Will Cause List Elements
// to be sorted on age values.
Public int COMPARETO (Person P)
{
RETURN AGE - P.AGE;
}
Public override string toString ()
{
Return Name ":" AGE;
}
// Must Implement Equals.
Public Bool Equals (Person P)
{
Return (this.Age == P.AGE);
}
}
Class Program
{
Static void
Main
(String [] ARGS)
{
// Declare and instantiate a new generic sortedlist class.
// Person is the Type Argument.
SortedList
// CREATE NAME AND AGE VALUES TO INITIALIZE PERSON Objects.
String [] Names = new string [] {"Franscoise", "Bill", "Li", "Sandra", "Gunnar", "Alok", "Hiroyuki", "Maria", "Alessandro", "Raul"} ; int [] AGES = New int [] {45, 19, 28, 23, 18, 9, 108, 72, 30, 35};
// Populate the list.
For (int x = 0; x <10; x )
{
List.addhead (New Person (Names [x], Ages [x]));
}
// Print Out UNSORTED LIST.
Foreach (Person P in List)
{
Console.writeline (p.toString ());
}
// sort the list.
List.bubblesort ();
// Print Out Sorted List.
Foreach (Person P in List)
{
Console.writeline (p.toString ());
}
Console.WriteLine ("DONE");
}
}
You can specify multiple interfaces as constraints in one type:
Class Stack
An interface can define multiple types of parameters as follows:
IDictionary
The inheritance rules for interfaces and classes are the same:
// okay.
ImyInterface: ibaseinterface
// okay.
ImyInterface
// okay.
ImyInterface
// Error.
ImyInterface
The specific class can realize the closed construction interface, as follows:
Class myclass: ibaseinterface
The generic class can achieve generic interface or enclosed construct interface, as long as the class's parameter list provides all the parameters required for the interface, as follows:
// okay.
Class myclass
// okay.
Class Myclass
Frequency class, generic structure, generic interfaces have rules that are also overloaded. For more information, see the generic method.
Seven, generic method
The generic method is a method of claiming type parameters, as follows:
Void Swap
{
T Temp;
Temp = LHS;
LHS = rhs;
RHS = TEMP;
}
The following sample code shows an example of calling a method with INT as a type of parameters:
INT A = 1;
INT b = 2;
// ...
SWAP
You can also ignore type parameters, and the compiler will inibreter of it. The following is called the SWAP code and the above example is equivalent:
SWAP (A, B);
Static methods and example methods have the same type inference rules. The compiler can infer the type parameters based on the incoming method parameters; and cannot be judged according to constraints or return values. Therefore, the type inference is invalid for the method without parameters. Type Inference When compiled, and before the compiler parses the overload method flag. The compiler application type inference logic for all the generic methods of all the same name. In the stage of decision (Resolution), the compiler contains only generic classes that have been submitted successful. For more information, see C # 2.0 Specifications, 20.6.4
Type parameter infer
In generic methods, the non-extensive method can access the type parameters in the class, as follows:
Class myclass
{
// ...
Void Swap (Ref T LHS, REF T rHS) {...}
}
You cannot [JX1] define a generic method, and its class has the same type of parameters; trying to do so, the compiler will generate a warning CS0693.
Class MyList
{
// cs0693
Void mymethod
}
Class MyList
{
// this is okay, but not common.
Void SomeMethod () {...}
}
Use constraints can use more types of parameters in the method. This version of SWAP
Void Swapifreater
{
T Temp;
IF (lhs.comPareto (RHS)> 0)
{
Temp = LHS;
LHS = rhs;
RHS = TEMP;
}
}
The generic method is overloaded by multiple type parameters. For example, the following methods can be placed in the same class:
Void Dosomething () {}
Void Dosomething
Void Dosomething
Eight, generic commission
Whether in the class definition or outside the class definition, the commission can define its own type parameters. The code that references generic commission can specify type parameters to create a closed constructed type, which is the same as instantiating generic classes or calling generic methods, as shown in the following example:
Public Delegate Void MyDelegate
Public Void Notify (INT I) {}
// ...
MyDelegate
C # 2.0 has a new feature called method group conversion, specific agent and generic agent types can be used. Method group conversion can write the above line to simplify the grammaxial:
MyDelegate
The type parameters of generic classes can be used in the same way as the classes of the generic classes.
Class Stack
{
T [] items;
Int index
// ...
Public Delegate Void StackDelegate (t [] items);
}
Quote the entrusted code must specify the type parameters of the class, as follows:
Stack
Stack
Public void stackeventhandler
Class Stack
{
// ...
Public Class Stackeventargs: Eventargs {...}
Public Event Stackeventhandler
Protected Virtual Void OnstackChanged (Stackeventargs A)
{
Stackevent (this, a);
}
}
Class myclass
{
Public Static Void HandleStackChange
}
Stack
Myclass mc = new myclass ();
S.stackeventhandler = mc.handlestackchange;
Nine, default keywords in generic code
One problem in generic and generic methods is how to assume the default value to the parameterization type, at which point the following two points cannot be known in advance:
L T will be a value type or a reference type
l If t is a value type, then T will be numeric or structure
For a variable T of a parameterized type T, the T = NULL statement is legal only when T is a reference type; T = 0 is only valid for the value, and the structure is not. The solution to this problem is to use the default keyword, which returns to the reference type, and returns zero the value of the value type. For the structure, it will return to the structure each member, and the value is the value type or the reference type, returns zero or empty. The following MYLIST
Public Class MyList
{
// ...
Public t getnext ()
{
T Temp = Default (T);
IF (Current! = NULL)
{
Temp = current.data;
Current = Current.next;
}
Return Temp;
}
}
Ten, C templates and C # generics
(Not translated)
C # Generics and C templates are both language features that provide support for parameterized types. However, there are many differences between the two. At the syntax level, C # generics are a simpler approach to parameterized types without the complexity of C templates. In addition, C # does not attempt to provide all of the functionality that C templates provide. At the implementation level, the primary difference is that C # generic type substitutions are performed at runtime and generic type information is thereby preserved for instantiated objects. for more information, see Generics In The Runtime.The Folllowing Aren C # generics and C Templates:
· C # generics do not provide the Same Amount of Flexibility AS C Templates. For Example, IT IS Not Possible To Call Arithmetic Operators In A C # generic class, although it is possible to call user defined Operators.
· C # Does Not Allow Non-Type Template Parameters, SUCH AS Template C
· C # does not support evicit specialization; That IS, A Custom IMPLEMENTATION OF A TEMPLATE for A Specific Type.
· C # Does Not Support Partial Specialization: a Custom IMplement for A Subset of The Type Arguments.
· C # does not allow the Type Parameter to be used as the base class for the generiic type.
· C # does not allow type parameters to have default types.
· In C #, a Generic Type Parameter Cannot Itself becomter, Although Constructed Types Can Be Used As Generals. C Does Allow Template Parameters.
· C allows code that might not be valid for all type parameters in the template, which is then checked for the specific type used as the type parameter. C # requires code in a class to be written in such a way that it will work with any type that satisfies the constraints For example, in C it is possible to write a function that uses the arithmetic operators and -. on objects of the type parameter, which will produce an error at the time of instantiation of the template with a type that Does Not Support these Operators. C # disallows this; The only language constructs allowed area Those That Can Be Deduced from the constraints. Eleven, running in runtime
Specialized Generic Types Are Created ONCE for Each Unique Value Type Used as a parameter.
When the generic class or generic method is compiled as a Microsoft Intermediate Language (MSIL), the metadata it contains defines its type parameters. The MSIL used for generic types is also different depending on the type parameters given.
When a generic type is constructed as a parameter as a parameter, a dedicated generic type is created using the parameters provided by the provided parameters or the appropriate position in MSIL. The runtime will create a dedicated generic type for each unique value of the parameter. [Jx3]
For example, suppose your program code is called a stack consisting of integer, such as:
Stack
At this point, it is used to properly replace its type parameters properly, generate a dedicated version of the stack. Thereafter, the program code is used to run the dedicated stack that has been created when the program code is used. The following example creates an instance of two integer stacks, which share a Stack
Stack
Stack
However, if another value type-as a long-integrated or user-defined structure-as a parameter, another stack is created in other parts of the code, then another version of the generic type is generated. This time is the appropriate location for the long integer to MSIL. Since each dedicated generic class contains value type, no reproduction is required.
For reference types, generic work is slightly different. When the generic class is constructed for the first time, a dedicated generic class is created in MSIL at runtime, where the parameters are replaced by the object reference. Thereafter, whenever a reference type is used as a parameter to instantiate a constructed type, it is ignored that its type and the generic class of previously created dedicated versions are used. This may be due to the same size of all references.
For example, if you have two reference types, a Customer class and an Order class; further assume that you have created a Customer's stack:
Stack
At this time, a dedicated version of the stack is generated at runtime, which is used to store references to the object, not the stored data. If the next line of code creates a stack of another reference type, named ORDER:
Stack
Unlike the value type, the runtime does not create a dedicated version of the ORDER type. Instead, a dedicated version stack instance is created at runtime, and the variable order is point to this instance. If it is the code that is a stack of Customer type:
Customers = New Stack
As previously created by the Order Type, another instance of a dedicated stack is created, and the pointers included in the pointer points to memory consistent with the Customer class. Since the quantity of different programs quote is large, the compiler only creates a special class only for the general type of the reference type, so the C # is greatly reduced to the utility of genericity reduces the code expansion.
In addition, when using the type parameters to implement a generic C # class, you want to know that it is a type or a reference type, which can determine its true type and its type parameters by reflecting at runtime.
Twelve, generics in the basic class library
The 2.0 version of the .NET Framework class library provides a new namespace, System.Collections.Gener, which contains some generic container classes and related interfaces that have been used. These classes and interfaces are more efficient and type safe than the non-float containers provided by the earlier version .NET framework. Before designing, you can implement a custom container class, please consider whether or not one of the listed classes is used.
The following table lists new generic classes and interfaces, next to the corresponding non-flood type and interface. Pay special attention to some places, such as List
Wild class or interface
description
Corresponding non-extensive type
Collection
Icollection
Provide base classes for generic containers
CollectionBase
ICollection
Comparer
IComparer
IComparable
Compares whether the objects of the two same generic types are equal, can be sorted.
Comparer
Icomparer
Icomparable
Dictionary
IDictionary
Indicates the key / value of the key to organize.
Hashtable
IDictionary
Dictionary
Represents a collection of Dictionary
NONE.
Dictionary
Represents a collection of Dictionary
NONE.
Ienumerable
Ienumerator
Indicates a collection of foreach iterations.
Ienumerable
Ienumerator
KeyedCollection
Indicates a collection of key values.
KeyedCollection
LinkedList
Represents a two-way linked list.
NONE.
LinkedListNode
Indicates the node in LinkedList
NONE.
List
IList
ArrayList
IList
Queue
Represents the advanced first set of objects.
Queue
ReadonlyCollection
Provide base classes for generic read-only containers.
ReadonlyCollectionBase
SortedDictionary
Indicates a collection of key / value pairs, these keys and values button routine and can be accessed according to the key to implement the IComparer
Sortedlist
Stack
A simple backward process that represents an object.
Stack