C # Generic,

Source: Internet
Author: User

C # Generic,
I. Overview of generics

Generic classes and generic methods combine reusability, type security, and efficiency. They are not suitable for non-generic classes and methods. Generics are widely used in containers (collections) and methods for container operations .. NET Framework 2.0 Class Library provides a new namespace System. Collections. Generic, which contains some new Generic-based container classes.

 

Ii. Advantages of generics

For earlier general language runtime and C # Language limitations, generics provide a solution. Previous types of generalization were implemented by mutual conversion between types and global base class System. Object. The ArrayList container class of the. NET Framework base class library is an example of this limitation. ArrayList is a convenient container class, which can store any reference type or value type without any changes.

ArrayList list = new ArrayList ();
List. Add (1 );
List. Add (1, 175.50 );
List. Add ("hello kitty ");

Double sum = 0;
Foreach (int value in list)
{
Sum + = value;
}

Disadvantages:

Convenience comes at a cost. This requires that any reference type or value type added to the ArrayList be implicitly converted to System. Object. If these elements are of the value type, they must be boxed when added to the list; when they are retrieved again, they must be split. The type conversion, packing, and unpacking operations both reduce the performance. When an iteration is required for a large container, the effects of packing and unpacking may be significant. Another limitation is the lack of type check during compilation. When an ArrayList converts any type to an Object, it cannot prevent errors such as sum + = vlaue in the client code during compilation;

In the Generic List <T> container in the System. Collections. Generic namespace, add elements to the container, as shown in the following code:

List <int> listInt = new List <int> ();
ListInt. Add (1, 100 );
ListInt. Add (1, 200 );
ListInt. Add (123.112); // compilation Error
ListInt. Add ("heel"); // compilation Error

Double sum = 0;
Foreach (int value in list)
{
Sum + = value;
}

Compared with ArrayList, the unique List <T> syntax added in the Customer Code is Declaration and type parameter in instantiation. The slightly complicated code returns that the table you create is not only safer than the ArrayList, but also faster, especially when the elements in the table are of the value type.

Iii. generic type parameters

In the definition of a generic type or generic method, a type parameter is a placeholder (placeholder), usually a capital letter (you can also use any non-keyword or reserved word name ), such as T. When the Customer Code declares and instantiates a variable of this type, T is replaced with the data type specified by the customer code. Generic classes, such as the List <T> class given in generics, cannot be used as-is because they are not a real type and are more like a type blueprint. To use MyList <T>, the Customer Code must specify a type parameter in angle brackets to declare and instantiate a constructed type ). The type parameter of this specific class can be any type recognized by the compiler. You can create any number of constructed type instances, each of which uses different type parameters, as shown below:

List <int> listInt = new List <int> ();
List <float> listFloat = new List <float> ();
List <String> listString = new List <String> ();

 

Iv. Constraints on generic parameters

Generics provide the following five constraints:

Constraints Description
Where T: struct Parameter type must be Value Type
Where T: class The parameter type must be a reference type.
Where T: new () The parameter type must have a public no-argument constructor. When used together with other constraints, the new () constraint must be placed at the end.
Where T: <Base Class Name> The parameter type must be the specified base type or a subclass derived from the specified base type.
Where T: <Interface Name> The parameter type must be the implementation of the specified interface or specified interface. You can specify constraints for multiple interfaces. Interface constraints can also be generic.

Unrestricted type parameters:

No type constraint: When a constraint is a generic type parameter, it is called Naked type constraints ).

Class List <T>
{
Void Add <U> (List <U> items) where U: T
{
}
}

In the preceding example, T in the context of the Add method is a non-type constraint, while T in the context of the List class is an unrestricted type parameter.

Non-type constraints can also be used in the definition of generic classes. NOTE: If there is no type constraint, you must declare it in angle brackets together with other type parameters:

// Naked type constraint

Public class MyClass <T, U, V> where T: V

Because the compiler only considers that the non-type constraint is inherited from System. Object, the use of generic classes with no type constraints is very limited. When you want to force two type parameters to have an inheritance relationship, you can use a non-type constraint on the generic type.

V. Generic Type

Generic classes encapsulate operations that do not target any specific data type. Generic classes are often used in container classes, such as linked lists, hash tables, stacks, queues, and trees. Operations in these classes, such as adding or deleting elements to a container, execute almost the same operation regardless of the type of the stored data.

Generally, a generic class is created from an existing specific class, and a type is changed to a type parameter each time until the optimal balance between general and availability is achieved. When creating your own generic class, you must consider the following:

  • Which types should be generalized to type parameters. The general rule is that the more types are represented by parameters, the more flexibility and reusability of the Code. Too much generalization will make the code hard to be understood by other developers.
  • If there are constraints, what type parameters need. A good habit is to use the maximum constraints as much as possible while ensuring that all types to be processed can be processed. For example, if you know that your generic class only intends to use the reference type, then the constraints of this class are applied. This prevents unintentional use of the value type. You can also use the as operator for T and check for null references;
  • Put the generic behavior in the base class or subclass. Generic classes can be used as base classes. This should also be considered in the design of non-generic classes. Inheritance rules for generic base classes;
  • Whether to implement one or more generic interfaces. For example, to design a class that creates elements in a generic containerIComparable <T>, Where T is the parameter of this class.

For a generic Node <T>, the customer code can specify a type parameter to create a closed Constructor (Node <int>) or retain the type parameter unspecified, for example, specify a generic base class to create an open Constructor (Node <T> ). Generic classes can inherit from specific classes, closed construction types, or open construction types:

// Concrete type
Class Node <T>: BaseNode
// Closed constructed type
Class Node <T>: BaseNode <int>
// Open constructed type
Class Node <T>: BaseNode <T>

A non-generic class can inherit the self-closed construction base class, but cannot inherit the self-open construction base class. This is because the Customer Code cannot provide the type parameters required by the base class:

// No error.
Class Node: BaseNode <int>
// Generates an error.
Class Node: BaseNode <T>

Generic classes can inherit from open constructor classes. Except for the type parameters shared with subclass, you must specify the type for all type parameters:

// Generates an error.
Class Node <T>: BaseNode <T, U> {...}
// Okay.
Class Node <T>: BaseNode <T, int> {...}

The parameter types and constraints must be specified for generic classes inherited from open structure types:

Class NodeItem <T> where T: IComparable <T>, new (){...}
Class MyNodeItem <T>: NodeItem <T> where T: IComparable <T>, new (){...}

Wildcard types can use multiple types of parameters and constraints:

Class KeyType <K, V> {...}
Class SuperKeyType <K, V, U> where U: IComparable <U>, where V: new (){...}

Open and closed construction types can be used as parameters of methods:

Void Swap <T> (List <T> list1, List <T> list2 ){...}
Void Swap (List <int> list1, List <int> list2 ){...}

 

6. Generic Interfaces

When an interface is specified as a type parameter, only the type that implements this interface can be used as a type parameter.

You can specify multiple interfaces as constraints in a type as follows:

Class Stack <T> where T: IComparable <T>, IMyStack1 <T> {}

One interface can define multiple types of parameters, as shown below:

IDictionary <K, V>

The inheritance rules for interfaces and classes are the same:

// Okay.
IMyInterface: IBaseInterface <int>
// Okay.
IMyInterface <T>: IBaseInterface <T>
// Okay.
IMyInterface <T>: IBaseInterface <int>
// Error.
IMyInterface <T>: IBaseInterface2 <T, U>

A specific class can implement the closed constructor interface as follows:

Class MyClass: IBaseInterface <string>

A generic class can implement a generic interface or a closed constructor interface, as long as the parameter list of the class provides all the parameters required by the interface, as follows:

// Okay.
Class MyClass <T>: IBaseInterface <T>
// Okay.
Class MyClass <T>: IBaseInterface <T, string>

Generic classes, generic structures, and generic Interfaces All have rules that are reloaded using the same method.

 

VII. Generic Method

The generic method is known as the type parameter method, as follows:

Void Swap <T> (ref T lhs, ref T rhs)
{
T temp;
Temp = lhs;
Lhs = rhs;
Rhs = temp;
}

The following sample code shows an example of calling a method using int as a type parameter:

Int a = 1;
Int B = 2;
//...
Swap <int> (a, B );

You can also ignore the type parameter and the compiler will deduce it. The following code calls Swap is equivalent to the above example:

Swap (a, B );

Static methods have the same type inference rules as instance methods. The compiler can infer the type parameter based on the passed-in method parameter, but cannot judge it separately based on the constraint or return value. Therefore, type inference is invalid for methods without parameters. Type inference occurs during compilation and before the compiler resolves the flag of the overloaded method. The compiler applies the type inference logic to all generic methods with the same name. In the resolution reload stage, the compiler only contains the generic classes whose types are inferred successfully.

In a generic class, non-generic methods can access type parameters in the class:

Class List <T>
{
Void Swap (ref T lhs, ref T rhs ){...}
}

In a generic class, define a generic method with the same type parameter as the class in which it is located. In this case, the compiler generates a warning CS0693.

Class List <T>
{
Void Swap <T> (ref T lhs, ref T rhs ){}
}

Warning CS0693: The type parameter "T" is the same as the type parameter in the external type "List <T>"

In a generic class, define a generic method to define an undefined type parameter in a generic class: (not commonly used, usually used with constraints)

Class List <T>
{
Void Swap <U> (ref T lhs, ref T rhs) {}// not commonly used

Void Add <U> (List <U> items) where U: T {} // common
}

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 <T> (){}
Void DoSomething <T, U> (){}

8. default keywords in generics

One problem that may occur in generic classes and generic methods is how to assign the default value to a parameterized type. At this time, the following two points cannot be known in advance:

For variable T of a parameterized type t, the T = null statement is valid only when t is a reference type; t = 0 is valid only for values, but not for structures. The solution to this problem is to use the default keyword, which returns NULL for the reference type and zero for the value type. For a structure, it returns each member of the structure, and returns zero or Null Based on whether the member is a value type or a reference type.

Class GenericClass <T>
{
T GetElement ()
{
Return default (T );
}
}

Related Article

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.