Understanding generics from simple examples
It is said that a film and television company selects an idol leading actor, and the director said, the height of the actor is king. The following code is available:
Copy codeThe Code is as follows: // The actor entity class
Public class Boy
{
// Name
Private string mName;
// Height
Private int mHeight;
Public string Name {
Get {return this. mName ;}
}
Public int Height {
Get {return this. mHeight ;}
}
Public Boy (string name, int height ){
This. mName = name;
This. mHeight = height;
}
}
// Select actors
Public class Compare
{
// The Director guides the birth of a Super Girl and enjoys one-on-one PK.
Public Boy WhoIsBetter (Boy boy1, Boy boy2)
{
If (boy1.Height> boy2.Height)
{
Return boy1;
}
Else
{
Return boy2;
}
}
}
// Test
Static void Main (string [] args)
{
Boy boy1 = new Boy ("pan Changjiang", 165 );
Boy boy2 = new Boy ("Andy Lau", 175 );
Console. WriteLine (new Compare (). WhoIsBetter (boy1, boy2). Name );
Console. ReadLine ();
}
The code is very simple. Boy is the real class of the actor, including the attributes of the name and height fields; WhoIsBetter in the Compare class is the selection logic method, which is responsible for selecting the higher ones of the two actors; test results: andy Lau wins.
All industries are the same, and demand changes are everywhere. The next day, the actress needs to be selected. The director said, actress, SLIM is king. As a result, the code changed, the actress entity class was added, and the actress selection method was added:Copy codeThe Code is as follows: // Add an actress entity
Public class Girl
{
// Name
Private string mName;
// Weight
Private int mWeight;
Public string Name
{
Get {return this. mName ;}
}
Public int Weight
{
Get {return this. mWeight ;}
}
Public Girl (string name, int weight ){
This. mName = name;
This. mWeight = weight;
}
}
// Add an actress Method to the actor selection class
Public class Compare
{
// The height of the actor is Wang Dao
Public Boy WhoIsBetter (Boy boy1, Boy boy2)
{
If (boy1.Height> boy2.Height)
{
Return boy1;
}
Else
{
Return boy2;
}
}
// Actress SLIM is king
Public Girl WhoIsBetter (Girl girl1, Girl girl2)
{
If (girl1.Weight <girl2.Weight)
{
Return girl1;
}
Else
{
Return girl2;
}
}
}
// Test
Static void Main (string [] args)
{
Boy boy1 = new Boy ("pan Changjiang", 165 );
Boy boy2 = new Boy ("Andy Lau", 175 );
Girl girl1 = new Girl ("Gong Li", 120 );
Girl girl2 = new Girl ("Zhou Xun", 80 );
Console. WriteLine (new Compare (). WhoIsBetter (boy1, boy2). Name );
Console. WriteLine (new Compare (). WhoIsBetter (girl1, girl2). Name );
Console. ReadLine ();
}
As a result, Andy Lau, who is taller, and Zhou Xun, who is lighter, was chosen. The director was very satisfied. But from the perspective of programming, this code is obviously not perfect. On the first day, I will select the leading role, the next day I will select the leading role, and then I will select the supporting role and the masses ...... currently, only by constantly adding methods to the Compare class can the director's requirements be met. The method will increase and the code will grow. So I decided to modify the WhoIsBetter method so that it could support comparison between male, female, male, female, male, and female:Copy codeThe Code is as follows: // <summary>
/// Actor: implements the IComparable Interface
/// </Summary>
Public class Boy: IComparable
{
// Name
Private string mName;
// Height
Private int mHeight;
Public string Name {
Get {return this. mName ;}
}
Public int Height {
Get {return this. mHeight ;}
}
Public Boy (string name, int height ){
This. mName = name;
This. mHeight = height;
}
Public int CompareTo (object obj)
{
// Compare height
Return this. mHeight-(Boy) obj). Height;
}
}
/// <Summary>
/// ACTRESS: implements the IComparable Interface
/// </Summary>
Public class Girl: IComparable
{
// Name
Private string mName;
// Weight www.2cto.com
Private int mWeight;
Public string Name
{
Get {return this. mName ;}
}
Public int Weight
{
Get {return this. mWeight ;}
}
Public Girl (string name, int weight ){
This. mName = name;
This. mWeight = weight;
}
Public int CompareTo (object obj)
{
// Compare weight
Return (Girl) obj). Weight-this. mWeight;
}
}
First, let the entity class support custom comparison. The actors are taller and actresses are heavier. Custom comparison is implemented through the IComparable interface. in C #, all types that can be compared, such as int, double, and char, implement the IComparable interface. The IComparable interface is not described here. Please refer to the relevant information on your own.Copy codeThe Code is as follows: public class Compare
{
// All objects
Public object WhoIsBetter (object obj1, object obj2)
{
Object result = obj2;
// Determine that the comparison type must be the same
If (obj1.GetType () = obj2.GetType ())
{
Switch (obj1.GetType (). ToString ())
{
// Select an actor
Case "Generic. Boy ":
If (Boy) obj1). CompareTo (obj2)> 0)
{
Result = obj1;
}
Break;
// Actress Selection
Case "Generic. Girl ":
If (Girl) obj1). CompareTo (obj2)> 0)
{
Result = obj1;
}
Break;
// Extended int type comparison
Case "System. Int32 ":
If (System. Int32) obj1). CompareTo (obj2)> 0)
{
Result = obj1;
}
Break;
}
}
Return result;
}
}
Modifying the WhoIsBetter method not only supports comparison of actors and actresses, but also adds int-type comparison to demonstrate its scalability.Copy codeThe Code is as follows: // Test
Static void Main (string [] args)
{
Boy boy1 = new Boy ("pan Changjiang", 165 );
Boy boy2 = new Boy ("Andy Lau", 175 );
Girl girl1 = new Girl ("Gong Li", 120 );
Girl girl2 = new Girl ("Zhou Xun", 80 );
Console. WriteLine (Boy) new Compare (). WhoIsBetter (boy1, boy2). Name );
Console. WriteLine (Girl) new Compare (). WhoIsBetter (girl1, girl2). Name );
Console. WriteLine (new Compare (). WhoIsBetter (boy1.Height, boy2.Height ));
Console. WriteLine (new Compare (). WhoIsBetter (girl1.Weight, girl2.Weight ));
Console. ReadLine ();
}
Test results:
Andy Lau
Zhou Xun
175
120
OK. Up to now, it seems to be perfect. The ratio of actors to height and actress to weight also supports the int type ratio. The WhoIsBetter method is reusable. If necessary, it can be expanded in the future, compare any two objects. Before the appearance of generics, it seems to be perfect, but this is just relative. Let's take a look at the weakness of the current Code:
Weakness 1: reusability of methods
Suppose we want the WhoIsBetter method to support more types, such as the Basic double, char, and bool types, the comparison of supporting roles that the Director may propose in the future, and the comparison of the masses, therefore, the internal code of the method must be constantly extended, which brings great maintenance costs.
Weakness 2: type security issuesCopy codeThe Code is as follows: // Test
Static void Main (string [] args)
{
Boy boy1 = new Boy ("pan Changjiang", 165 );
Boy boy2 = new Boy ("Andy Lau", 175 );
Girl girl1 = new Girl ("Gong Li", 120 );
Girl girl2 = new Girl ("Zhou Xun", 80 );
Console. WriteLine (Boy) new Compare (). WhoIsBetter (boy1, girl1). Name );
Console. ReadLine ();
}
I will compare the above Code with Pan Changjiang and Gong Li. Although the omnipotent object brings us convenience and risks, this code can be compiled completely, but exceptions may occur during the runtime, and the girl object cannot be converted to the Boy type, in reality, going to South Korea can be changed, but it is definitely not in the code. Therefore, this method is like a time bomb. Accidentally passing wrong parameters will cause serious consequences and the compilation phase will not be found at all.
Weakness 3: performance problems caused by binning
When the int parameter is passed to the WhoIsBetter method, converting the object to an int causes the unboxing operation:
If (System. Int32) obj1). CompareTo (obj2)> 0)
Decompilation to obtain MSIL:
IL_0093: unbox. any [mscorlib] System. Int32
C # is a strongly typed language, but Box and Unbox cannot be avoided as long as the reference type and value type are converted to each other. For more information about packing and unpacking, see relevant materials.
Understanding generics
OK. Now the generic model is available. The following excerpt describes the generic model in MSDN: both generic and generic methods are reusable, secure, and efficient, this is not possible for non-generic and non-generic methods. These three points are consistent with the above example.
Let's take a look at the solutions for Using Generics:Copy codeThe Code is as follows: public class Compare <T> where T: IComparable
{
Public T WhoIsBetter (T t1, T t2)
{
If (t1.CompareTo (t2)> 0)
{
Return t1;
}
Else
{
Return t2;
}
}
}
// Test
Static void Main (string [] args)
{
Boy boy1 = new Boy ("pan Changjiang", 165 );
Boy boy2 = new Boy ("Andy Lau", 175 );
Girl girl1 = new Girl ("Gong Li", 120 );
Girl girl2 = new Girl ("Zhou Xun", 80 );
Console. WriteLine (new Compare <Boy> (). WhoIsBetter (boy1, boy2). Name );
Console. WriteLine (new Compare <Girl> (). WhoIsBetter (girl1, girl2). Name );
Console. WriteLine (new Compare <int> (). WhoIsBetter (boy1.Height, boy2.Height ));
Console. WriteLine (new Compare <string> (). WhoIsBetter (boy1.Name, girl1.Name ));
Console. ReadLine ();
}
This code is superior to non-generic in elegance and greatly improves reusability. It can be said that it supports comparison of all types, as long as this type implements the IComparable interface, and once and for all, you do not need to make any extension within the method.
Public class Compare <T> where T: IComparable {
//...
}
The definition of a generic class is followed by the class name <T>. This is a special generic syntax. T indicates the type passed in. You can also replace it with other letters.
Where T: IComparable, which can be understood literally. This section indicates the type constraints on T. The program is executed according to the will of the people. According to the previous example, if the program is inexplicably compared to two objects, it cannot know how to compare them. Therefore, we must tell the program that T must be a comparable type, and T must implement the IComparable interface.
For generic parameter constraints, MSDN provides a table:
Constraints
T: The structure type parameter must be a value type. You can specify any value type except Nullable.
T: The class type parameter must be of the reference type. This applies to any class, interface, delegate, or array type.
T: The new () type parameter must have a public constructor without parameters. When used with other constraints, the new () constraint must be specified at the end.
T: The <Base Class Name> type parameter must be a specified base class or derived from the specified base class.
T: <Interface Name> the type parameter must be the specified interface or implement the specified interface. Multiple interface constraints can be specified. The constraint interface can also be generic.
T: The type parameter provided by U for T must be a parameter provided by U or derived from a parameter provided by U.