There are types of things in everyday life, such as when we say "a woman", then "woman" is the type of person. We can say that "women are made of water", so the listener knows that this is the "female" type of person. If you go to the butcher's to buy meat, you can say to the boss "I want 10 pounds of pork", then the boss must know you are to "pig" this type of meat. In everyday life These languages are of a type, but in everyday life there are some languages that are not of the same type. For example, we often say "people are greedy", there is no type of people here, the listener knows that all the people; we can also say "give me 10 pounds of meat" at the butcher's, and the butcher knows you want pork.
The programming language must be able to represent the data in the real world, and for the C # language, data types can be used to accurately describe the data. In fact, this kind of programming language is called the strong type language, the data which appears in such language must have the data, such language also has many, such as C + +, Java, Python and so on. Weakly typed languages, such as VB, JavaScript, and so on, do not have a data type concept. We can see the pros and cons of each of these two types of meat from the butcher shop. Strongly typed language can clearly express the logic but the expression is too wordy, whether it is the butcher shop owner or the person next to hear "I want 10 pounds of pork" this sentence can know exactly what you mean. Weak type language is characterized by simple expression but logic prone to confusion, such as you can also point to the pork said "to 10 Jin", it is obvious that only the butcher shop owner first understand your gestures to understand, easy to cause logic confusion.
The computer program is the language of push, in the middle of a line of logic error will lead to the final result error, so from this point of view, obviously in the purchase of pork this problem strongly typed language wins. Let's look at the expression of the human being, for the phrase "man is greedy", is to describe a universal law. For this problem is described in the traditional strong-type language is "women are greedy, men are greedy", this is obviously very verbose, this is also a strong type of language has a flaw. For example, in the program often use some general-purpose algorithms, in strong-type language to write these common algorithms will be the same as above, the need for each data type to provide a similar algorithm. Generic technologies are used to solve such problems.
Focus:
? Understanding the concept of generics
? Definition and application of generic type
? Generic class
Preview Lessons:
? The concept of generics
? How to define generics and their applications
? How to use generic classes
9.1 Why generics are used
What would you do if you were to write a two-digit method in C #? If the two number is an integer, you can define the following method:
int Add (int a,int b)
{return a+b; }
If you are asking for a number of two double types, you can define the following methods:
Static double Add (double a,double b)
{return a+b; }
If the numeric value of the string is added, then you can define the following method:
Static double Add (string a,string b)
{
Return double. Parse (a) +double. Parse (b);
}
If one day the program needs to upgrade, you need other data type summation algorithm, day does not char, long, decimal, etc., then what do you do? Do you want to continue overloading? Or do you want a better, more generic approach? We might think of using the object class, so you wrote the following generic algorithm:
Staticobject Add (object A,object B)
{
Decimal is the largest numeric type, so use it
return decimal. Parse (a) +decimal. Parse (b);
}
Static Voidmain (String[]args)
{
Decimal r1= (decimal) Add (3,3);
Decimal r2= (decimal) Add (3.3,3.3);
Decimal r3= (decimal) Add ("3.3", "3.3");
Console.WriteLine ("{0},{1},{2}", R1,R2,R3);
}
Staticobject Add (object A,object B)
{
Returnconvert.todecimal (a) +convert.todecimal (b);
}
Operation Result:
6,6.6,6.6
The technique used here is boxing and unpacking, the Add method first boxing all data types, so that they unify the type, then the type conversion and calculation, the result of the disassembly is the result of the request. is actually an application of the idea of "generics", where a general method is used to solve the sum operation of almost any numeric type two numbers. So it can be said that for this summation algorithm is generic, generic (does not require a specific data type).
But we can see from the code page above that it performs frequent boxing and unpacking operations, and we know that these operations are very lossy. In addition, the packing and unpacking code also appears to be "ugly"
Is there a better way for us to write this general-purpose algorithm because of the strong-type conversions we have to make every time? As a result, C # has introduced generics from version 2.0, and the two obvious benefits that generics can bring to us are---code clarity and reduced binning and unpacking.
9.2 C # Generics Introduction
Examples of generic methods that use generics to solve two-number exchanges:
Using System;
Class Program
{
static void Main (String[]args)
{
int i=1,j=2;
Console.WriteLine ("Before Exchange: {0},{1}", i,j);
Swap<int> (ref i,ref J); Exchange two numbers
Console.WriteLine ("After Exchange: {0}", i,j);
}
Exchange two-digit generic algorithm
static void swap<t> (ref t a,ref t B)
{
T Temp=a;
A=b;
B=temp;
}
}
Operation Result:
Before Exchange:
After Exchange: 2,1
This switching algorithm not only supports any numeric type, it also supports any type you can use in your program. Note that generics do not belong to any namespace, and, to be precise, generics are a compilation technique. In writing algorithms, generic technology allows us to use a type placeholder (or type parameter, where the placeholder is "T") as the identifier of the type, rather than specifying a particular type.
When we call this algorithm, the compiler uses the specified type instead of the type placeholder to establish an algorithm for this type. This is the generic technique, which allows you to write the algorithm without specifying a specific type, but the call must specify the specific type, when writing the algorithm using "<>" to specify the type placeholder, when the call is generally used "<>" to specify the specific data type.
In the example above, the placeholder for this generic method is "T", and we can think of a data type that is the type T, which can be used as the data type of the parameter and as the return value type of the method, as specified by the Swap<t>. You can also use the data type of a local variable inside a method. When we call this generic method through Swap<int> (ref I,ref J), all occurrences of "T" in the compile-time swap method are replaced by the "int" type, which is the equivalent of creating a
An int-type Exchange method, such as:
static void Swap (ref int A,REF int B)
{
int temp=a;
A=b;
B=temp;
}
L Code Reuse
The most prominent advantage of generics is the ability to reuse code. You can also see how much code has been saved from an example of the switching algorithm above. For a programmer, writing a good algorithm is a very important asset, for example, we have been using a variety of class libraries, these libraries are actually some good programmer encapsulation, we call directly is a code reuse process.
L Type safety
Type safety means that operations between types must be compatible and, conversely, types are unsafe. Type unsafe code will be at run time exception, such as two number of algorithms added, Convert.todecimal (a), A is the object type, a can be the value of "3.3", a can also be a normal string "Hello", If a is the latter then it must be an exception when performing a type conversion, so using Convert.todecimal (a) is an unsafe type, and the same method of summing is also a method of unsafe type. Generics are inherently strongly typed, and if you use an incompatible type to invoke a generic algorithm, the compiler will tell you the error, so generics are type-safe.
L Better Performance
Generics are more efficient than boxing and unpacking. Because the system needs to allocate memory for boxing, type conversions are required when unpacking, both of which are extremely cost-intensive. In particular, the use of generics is advocated in C #, especially in cases where large data volumes are executed, such as sorting, searching, and so on.
9.3 Generic definition and its application
Generics can be used to define generic methods, generic classes, generic interfaces, and so on. In the definition of these generic structures, a generic type parameter (or placeholder) must be specified, and the type parameter contains a generic type that we define, and we can define multiple generic types at once, such as a generic method swap<t,u,z> three generic types. Type parameters are typically placed after the defined class, method, interface, and other identifiers, and are included in the "<>".
A generic type name is also written with a certain rule:
The generic type name must consist of letters, numbers, underscores, and must begin with a character or underscore. For example, _t, T, TC are valid generic type names.
Make sure to use a meaningful generic type name, unless a single letter name can fully understand what it means, such as T.
L Consider using T as a generic type name, such as Class note<t>, when there is only a single generic type in the type parameter.
L advocates the prefix as a generic type name, such as Tkey,tvalue.
In the preceding example, generic type T is generally used, but in essence we can use any word that satisfies the requirements above. In fact, the definition rules for generic type names and class names or interface names are basically the same.
9.4 Generic struct-body
Structs are value types, and you can typically define struct types to represent some simple objects. For example, the system structure in front of us contact point, DateTime, and so on. However, these structs usually store one type of data, and we can define a generic struct that will hold any data and define the rules:
struct struct name < generic type list >
{
Structural body;
}
Note that the definition of a generic type identifier can only be placed after the struct name, and we define a
A generic struct of type point, at which the X and y of the struct can hold coordinate data of any numeric type. The code is as follows:
Classprogram
{
Defining generic struct and generic type T
struct point<t>
{
Public T X;
Public T Y;
}
Test the generic structure body
Static Voidmain (String[]args)
{
Specify type int for t
Point<int> a =newpoint<int> ();
- X=1;
A. y=2;
Console.WriteLine ("{0},{1}", A.X,A.Y);
}
}
Operation Result:
The
9.5 generic class
Generic classes encapsulate data or operations that do not belong to a specific data type. The most common type of generic class is a generic collection class, such as a list, hash table, stack, queue, tree, and so on. Operations on collections, such as adding, removing, sorting from a collection, are mostly done in the same way, regardless of the type of data stored, you can use generic techniques.
The data type used in a generic class can be a generic type, or it can be normal. The general rule is that the more generic types are used in a class, the more flexible the code becomes and the better the reusability. Note, however, that having too many generic types in a class can make it difficult for other developers to read or understand the class. The generic type that defines the class is also defined by the "<>" after the class name, and other elements of the class cannot define their own generic type except the method, but the generic type defined by the class can be used. The generic class definition rules are as follows:
Class name < generic type list >
{
Class Body
}
Example code:
Usingsystem;
Classprogram
{
Defining generic classes and generic type T
Private Class Node<t>
{
Private T data;
Public Node (T t)
{
data=t;
}
Public T Data
{
Get{return data;}
Set{data=value;}
}
}
static void Main ()
{
Node<int>node=newnode<int> (10000);
Console.WriteLine ("Data: {0}", node.) Data);
Node<string>snode=newnode<string> ("One Million");
Console.WriteLine ("Data: {0}", Snode. Data);
}
}
Operation Result:
Data: 10000
Data: One million
As mentioned earlier, there are a number of members in a class, such as fields, properties, methods, events, indexers, and so on, in which, in addition to methods, other class members cannot customize the generic type, only the generic type or system data type defined when the class is defined:
Classstudent<t,u>
{
private T name; Name
Private U[]score; Array of scores for each account
private int ucode; Numbering using System data types
Public U this[int N]//return a fraction
{
Get{return Score[n];
}
}
A method in a class can be generic, and the generic method defines the following rules:
Access modifiers return type method name < generic type list > (method parameter list)
Such as:
Public voidshow<t> (T a) {}
When using this generic method, you specify an actual data type for T, such as:
show<string> ("Hello");
The generic type defined in the generic type list of the method can appear anywhere in the method, including return values, parameters, methods, and of course not, as the following are legal:
Public tget<t> (t a) {return default (t);}
Public intget<t a) {return 0;}
Public tget<t> (int a) {return default (T);}
This uses the default keyword, which can take the defaults of the current type, which returns null for the reference type and zero for numeric types.
In addition, a generic overloaded method can occur in a class, such as:
Voiddowork () {}
Voiddowork<t> () {}
Voiddowork<t,u> () {}
Because the method is in a class, the data type in the generic method is three cases, one is the generic type of the class, one is the generic type of the generic method itself, and the other can be a system data type. Generic methods and non-generic methods or properties, indexers can call each other. Such as:
Classstudent<u>
{
Private U ID;
private string name;
public void Showhello ()
{
This. show<string> ("Hello"); Calling a generic method
}
public void Showid ()
{
This. Show<u> (ID);
}
private void Show<s> (S msg)
{
Console.WriteLine (msg);
}
}
The generic type of the class can only be used for this class, and the generic type of the method can only be used for this method. No matter who defines generics, once a generic type is defined, you can use it when the generic type is a real type.
9.6 Typical generic classes
. NET Framework class library, In the System.Collections.Generic and System.Collections.ObjectModel namespaces, a number of generic and generic interfaces are defined, many of which are collection classes, because the largest application of generics is embodied in the management of different types of objects in the re-collection.
The following table lists the. The generic and generic interfaces commonly used in the NET Framework:
Generic class |
Description |
List<t> |
Corresponds to the ArrayList collection class, you can dynamically adjust the collection capacity, indexed access to objects, support sorting, searching, and other common operations. |
Sortedlist<tkey,tvalue> |
Corresponds to the SortedList collection class, which represents Key/value to the collection, similar to the Sorteddictionary<tkey,tvalue> collection class, and SortedList has an advantage over memory. |
Queue<t> |
Corresponds to the Queue collection class, which is a first-in-one-out collection class, often applied to sequential storage processing. |
Stack<t> |
Corresponds to a Stack collection class, which is a last-in-first-out collection class. |
Collection<t> |
The base class that corresponds to the CollectionBase collection class, which is used to customize the generic collection, provides a protected method to implement the behavior of a custom generic collection collection<t> instances of which are modifiable. |
Dictionary<tkey,tvalue> |
Corresponds to the Hashtable collection class, which represents the collection class of the Key/value pair, and the key must be unique, whose element type is neither the type of the key nor the type of value, but the KeyValuePair type. |
Understanding and use of generics in C # 32