Create "one encoding, multiple use," which is the root cause of the introduction of generics. Known as templates in previous C + +, C # generics support independent encoding through algorithms and data structures. For example, a generic list means that you do not have to rewrite a strong-type collection again. In this article, the author will show you how easy it is to define and use generics-note that generics have long been considered the most advanced and difficult term.
First, Introduction
Generics are now considered an advanced, powerful term in any language. When I first contacted the template in C + +, I had some doubts about it. Later, I read Bjarne Stroustrop's "The design and Evolution of C + +" to find that the use of templates is just as easy as the macros in C and the simple string substitution templates that are used to replace them. In fact, templates and generics are the same thing-although their implementations are slightly different.
C # generics support defines an algorithm and its data type at the point of use. In some earlier versions of C #, we can prove that no generics can work, because each type is derived from a common base type-object. This means that programmers can define a stack class based on the object type and put everything on that stack (since everything is derived from object). However, an object stack means that a customer object, an integer object, and an imaginary object can be placed on an instance of the same stack. As a result, developers want to subclass data types to bind data types to what they want to interact with. For example, when writing a custom business object, we recommend defining a strongly typed collection that is derived from System.Collections.CollectionBase. The reason is simple: Based on the object definition everything is considered to be a weak type definition.
Experts in the industry were convinced decades ago that strong types are better than weak types, so. NET finally supports the strong type, which seems to be a natural thing. Strongly typed algorithms of course recommend typing parameters-which is exactly what we use in generics.
For more than 10 of years, we have been using the letter T as the name of the typed parameter. In this way, you can find T in any type of data provided by the user of the generic class. The key to using generics is simply to provide this t. The key to defining generics is to implement a method or class and replace T with a specific data type.
Generics in C # support some other refinement. For example, a method or class can have multiple parameterized types and the C # generics also support a WHERE constraint-it is used to specify the type of the typed parameter. For example, if a generic type must implement an interface IDisposable, then the C # Generics support the implementation of this restriction. In the end of the article we also have to look at the constraint problem.
Less gossip, let's get to the other.
ii. using Generic collections
Some people ask me, "Where is the promise of object-oriented programming (OOP)?" "My answer is to look at OOP in two ways: the OOP you use and the OOP you create. If we take a quick look at the OO framework such as the VCL of Microsoft's. Net,borland, and all the Third-party components, many advanced applications are almost impossible to create. So, we can say that OOP has achieved its promise. Yes, it's difficult and potentially frustrating to produce good OOP code, but remember, you don't have to go through OOP to achieve your goals. So, let's take a look at the use of generics first.
When you create a project with a quick development tool such as Visual Studio or C # Express, you see a reference reference to the System.Collections.Generic namespace. In this namespace, there are several generic data structures-all of which support typed collections, hashes, queues, stacks, dictionaries, and lists. To use these powerful data structures, all you have to do is provide data types.
Listing 1 shows how easy it is to define a customer object with a strongly typed collection.
Listing 1 This console application contains a customer class and a strongly typed collection of customers based on list<t>.
Using System;
Using System.Collections.Generic;
Using System.Text;
Namespace generics{
Class program{
static void Main (string[] args) {
List<customer> customers = new list<customer> ();
Customers. ADD (New Customer ("Motown-jobs"));
Customers. ADD (New Customer ("Fatman ')");
foreach (Customer C in Customers)
Console.WriteLine (C.customername);
Console.ReadLine ();
}
}
public class customer{
private string customerName = "";
public string customername{
get {return customerName;}
set {customerName = value;}
}
Public Customer (String customerName) {
This.customername = CustomerName;
}
}
}
Note that we have a strongly typed set-list<customer>-that does not need to write a code for the collection class itself. If we want to extend the list of Customer, we can derive a new class by inheriting from List<customer>.
Third, the implementation of a generic class
A reasonable way to implement a new function is to build on the original thing. We've learned about strong-type collections and know that a good technique for building generic classes is to use a specific class and delete data types. In other words, let's define a strongly typed set of customerlist, and look at what it's going to turn into a generic class.
Listing 2 defines a class customerlist. The latter part converts the customerlist into list<t>.
Listing 2 defines the class CustomerList:
Using System;
Using System.Collections;
Using System.Text;
Namespace generics{
public class customerlist:collectionbase{
Public customerlist () {}
Public Customer This[int index]{
get {return (Customer) List[index];}
set {List[index] = value;}
}
public int Add (Customer value)
{return List.add (value);}
}
}
Define class headers
If we define a generic class, we need to convert the class header into a generic class. All we need to do is to name the arguments and change the class name to a generic. List<t> has only one parameter T, and because we are working in a backward-compatible way, we know that the class name is list. Listing 3 shows the new class header for the class in table 2.
List 3 A generic class header displays parameterized parameter T.
Using System;
Using System.Collections;
Using System.Text;
Namespace generics{
public class List<t>: collectionbase {}
implementation of generic fields
If we need to convert any of the fields to generic fields, we'll simply change their type to T (or any of the parameters described in the field). The generic list does not require any fields, but assumes that there is a private integer field called foo-we will make it generic. We'll redefine it as follows:
Private T foo;
When the parameter T is populated into the class, the List T will also be populated with Foo.
vi. definition of generic methods
Next, we define some other attributes for the parameterized type that we need. This includes attributes, methods, and events. In our example, at every point where the customer appears, we replace it with the parameter T. The completed generic list class is displayed in Listing 4.
List 41 lightweight, parameterized generic list classes based on System.Collections.CollectionBase.
Using System;
Using System.Collections;
Using System.Text;
Namespace generics{
public class List<t>: collectionbase {
Public List () {}
Public T This[int Index] {
get {return (T) List[index];}
set {List[index] = value;}
}
public int Add (T value) {
return List.add (value);
}
}
}
To test the custom list, comment out the phrase using the System.Collections.Generic namespace and use the list<t> in Listing 4 in the code in Listing 1; it will work the same way.
Fully modified. NET list<t> is unnecessary and contains far more features than our example, but listing 4 shows how easy this mechanism is for defining custom generic classes.
Vii. Increasing type constraints
The last thing to discuss is constraints. A constraint is applied to a class or other attribute and uses the following syntax:
Where T:constraint_type
For example, any IDisposable interface that we want to use with a using statement, such as a SqlDataReader, must be implemented. This is because the using statement used in the following manner:
using (Form f = new form ()) {...}
Just like a try. Finally block work-always clears the newly created resource. It works very simply by requiring the CLR to emit a call to IDisposable.Dispose for the object created in the using statement. For example, in the preceding sentence, a new form is created, and Form.dispose is invoked before the using statement exits.
To impose on a generic class to ensure that the class implements the interface Idisposable, we will add the antecedent where t:idisposable. After imposing a constraint on the generic list in Listing 4, we will modify listing 4 as shown in Listing 5 below.
Listing 5 adds a constraint to the generic class to ensure that all the value T in our list<t> implements the interface IDisposable.
Using System;
Using System.Collections;
Using System.Text;
Namespace generics{
public class list<t>: CollectionBase where t:idisposable{
Public List () {}
Public T This[int index]{
get {return (T) List[index];}
set {List[index] = value;}
}
public int Add (T value) {return List.add (value);}
}
}
The value of the antecedent where can be a class, interface, struct, implementation of a parameterless public constructor, or a class with a particular base class. See the Help documentation for details.
Viii. Summary
Generics are designed to reduce the number of code that you repeatedly implement-just change the data type. Because abstract data structures, such as queues, stacks, and lists, are typical structure of a database, there is a complete understanding of the generic classes that are available for these things. You can go from. NET-by using existing generic classes, such as those in the System.Collections.Generic namespace.
It is certain that, for a long time, generics will bring increasing value to development like patterns and refactoring, and that new data structures can be converted into reusable code elements such as generics.