I have been frequently exposed to generic problems recently, so I have to learn about it. At first, I downloaded the tutorial video from the WebCast on MSDN (instructor Li Jianzhong ), this article first introduces the introduction of generics, hoping that users who have just started learning generics can get started faster and get down to the truth. First, let's take a look at the basic concepts of generics.
The most significant thing is that it parameterized the type and abstracted the type as a parameter, so that we can achieve better reuse of code in practical use, at the same time, it provides stronger type security and higher efficiency, but in terms of constraints, it only supports display constraints, so it is not so flexible. I think it can provide higher efficiency because generics adopt the "on-demand" mode during instantiation, that is, on-demand instantiation occurs In JIT (Just In Time) compile time.
Next, let's take a look at how to define a generic class. It's very simple. You just need to realize that the type has been parameterized here:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace GenericTest
{
Class Program
{
Static void Main (string [] args)
{
// Use string and int to instantiate the Test <T, S> class.
Test <string, int> t = new Test <string, int> ("SHY520", 22 );
// Call Method
T. SetValue ();
}
}
/** // <Summary>
/// Define a generic class, which has two type parameters: T, S
// Http://pw.cnblogs.com
/// </Summary>
/// <Typeparam name = "T"> type parameter </typeparam>
/// <Typeparam name = "S"> type parameter </typeparam>
Public class Test <T, S>
{
// Type parameters of generic classes can be used for class members.
Private T name;
Private S age;
Public Test (T Name, S Age)
{
This. name = Name;
This. age = Age;
}
Public void SetValue ()
{
Console. WriteLine (name. ToString ());
Console. WriteLine (age. ToString ());
}
}
}
The above example is not very appropriate, so that you can understand the definition and instantiation method of generics for beginners. As mentioned above, we have defined a generic class, so how can we implement the inheritance of generic classes? Here we need to satisfy any of the following two points:
1. In generic class inheritance, the type parameter of the parent class has been instantiated. In this case, the subclass is not necessarily a generic class;
2. the type parameter of the parent class is not instantiated, but comes from the subclass. That is to say, both the parent class and the subclass are generic classes, and both have the same type parameter;
// If this is the case, it is clear that the type T and S cannot be found.
Public class TestChild: Test <T, S> {}
// The correct method should be
Public class TestChild: Test <string, int> {}
Public class TestChild <T, S >:test <T, S> {}
Public class TestChild <T, S >:test <String, int> {}
Next, let's take a look at the generic interface. Its creation and inheritance rules are the same as the generic class mentioned above. Let's look at the following code:
Public interface IList <T>
{
T [] GetElements ();
}
Public interface IDictionary <K, V>
{
Void Add (K key, V value );
}
// The type parameter of the generic interface is either instantiated
// Either comes from the type parameter of the implementation class declaration
Class List <T>: IList <T>, IDictionary <int, T>
{
Public T [] GetElements () {return null ;}
Public void Add (int index, T value)
{}
}
Let's take a look at generic delegation. First, we define a delegate whose type parameter is T, and then use the delegate call method in the class:
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace GenericTest
{
// Define a delegate. The type parameter is T and the return value type is T.
// Generic delegation supports the application of type parameters on return values and parameters
Delegate string GenericDelete <T> (T value );
Class test
{
Static string F (int I) {return "SHY520 ";}
Static string G (string s) {return "SHY520 ";}
Static void Main (string [] args)
{
GenericDelete <string> G1 = G;
GenericDelete <int> G2 = new GenericDelete <int> (F );
}
}
}
Let's look at the generic method. The generic mechanism of c # only supports containing type parameters in the method declaration, that is, the generic method. Note that Generics do not support the use of type parameters on other class/interface members except methods, but these Members can be included in the generic type, you can also use generic type parameters. Another point to note is that generic methods can exist in generic types or non-generic types. Next, let's take a look at the Declaration, call, overload, and overwrite of generic types.
Using System;
Using System. Collections. Generic;
Using System. Text;
Namespace GenericTest
{
Class GenericClass
{
// Declare a generic Method
Public T getvalue <T> (T t)
{
Return t;
}
// Call the generic Method
// Note: When calling a generic method, instantiate the type parameter of the generic method.
Public int useMethod ()
{
Return this. getvalue <int> (10 );
}
// Reload the getvalue Method
Public int getvalue (int I)
{
Return I;
}
}
// The following example overwrites
// Note that when a generic method is overwritten, the constraint is inherited by default, and you do not need to re-specify the constraint relationship.
Abstract class Parent
{
Public abstract k test <K, V> (K k, V v) where K: V;
}
Class Child: Parent
{
Public override t test <T, S> (T t, S s)
{
Return t;
}
}
}
Finally, let's look at the constraints in generics:
The generic type in C # only supports the display constraints, because this ensures the type security required by C #, but the display constraints are not mandatory. If no constraints are imposed, generic parameters can only access System. public methods in Object type. Explicit Constraints are expressed by the where clause. You can specify "base class constraints", "interface constraints", and "constructor constraints ", there are four types of constraints: Value Type and reference type constraint. The following example is from the lecture PPT of instructor Li Jianzhong.
1. Base constraints:
Class A {public void F1 (){}}
Class B {public void F2 (){}}
Class C <S, T>
Where S: A // S inherited from
Where T: B // T inherited from B
{
// You can call F1 on a variable of type S,
// You can call F2 on a variable of the T type.
}
2. Interface Constraints
Interface IPrintable {void Print ();}
Interface IComparable <T> {int CompareTo (T v );}
Interface IKeyProvider <T> {T GetKey ();}
Class Dictionary <K, V>
Where K: IComparable <K>
Where V: IPrintable, IKeyProvider <K>
{
// You can call CompareTo on a variable of K type,
// Print and GetKey can be called on a variable of the V type.
}
3. constructor Constraints
Class A {public (){}}
Class B {public B (int I ){}}
Class C <T>
Where T: new ()
{
// T t = new T () can be used in it ();
}
C <A> c = new C <A> (); // yes. A has no parameter constructor.
C <B> c = new C <B> (); // error. B has no parameter constructor.
4. Value/reference type constraints
Public struct {}
Public class B {}
Class C <T>
Where T: struct
{
// T is a value type.
}
C <A> c = new C <A> (); // yes. A is A value type.
C <B> c = new C <B> (); // error. B is a reference type.