Generics are used very frequently in. NET, and in console applications, the default introduces the System.Collection.Generics namespace, which provides the generic:list<t> and dictionary<t that we often use Believe that they have been used to know their strength. There is also a simple generic type that we often use: system.nullable<t> We can:
System.Nullable<int> Nullableint; declares a nullable int type, because C # syntax simplifies this usually we do not write this way, but write: int? Nullableint The following highlights how to customize generics. defining generic classes creating generic classes is required in the class definition with angle brackets syntax: class mygenericclass<t>{ ...} T can be an arbitrary identifier, as long as you follow the naming convention. can be used to type the class member's return type, method parameter type, etc., such as: copy code class MYGENERICCLASS<T1, T2, t3>{ Private T1 t1object; Public MyGenericClass (T1 item) { T1object = item;& nbsp } Public T1 t1object { get {& nbsp return t1object; } }} Copy the code Note If you cannot assume what type is provided. The following code cannot execute: copy code class MYGENERICCLASS<T1, T2, t3>{ private T1 t1object; public MyGenericClass () { t1object = new T1 (); }} Copy the code because we don't know if T1 has a public default constructor. defAult keyword If we define a generic field, we want to initialize it in the constructor, but we don't know whether it's a reference type or a value type, then default is useful: public MyGenericClass () { T1object = default (T1);} If the value type is assigned a value of 0, the reference type is assigned the value NULL. constraint types When defining generics we can constrain the type, implemented by the WHERE keyword: class mygenericclass<t1> where T: constraint1,constraint{ ...} Constraint defines a constraint, with multiple constraints separated by commas, if there are multiple types: class mygenericclass<t1, t2> where t1:constraint1 where t2:constraint{ ...} Here are some available constraints constraints , &NB Sp Description &NB Sp where t:struct Use structural constraints, type T must be a value type wher E t:calss class constraint specified, type T must be reference type &N Bsp where t:interface Specify type T must be implemented as interface or implement Interface where T:base-class &NBS P The specified type T must be a base class or derive from the basic class & nbsp &NBSp where t:new () &NBS P specifying type T must have a default constructor The following combination of knowledge to give an example: (PS do not see the code is actually very simple patience to see) first define four classes Animal, Cow, chicken, and supercow copy code #region Animal virtual base class has a Name property Feed method and a virtual method makeanoise //Virtual base class has a Name property feed method and a virtual method makeanoise Public abstract class animal& nbsp { protected string name; public string name   ; { get { &NBSP ; return name; } &NBS P set { name = value; &NBSP; } } public Animal () { name = "The animal with no name"; } &NBSP ; Public Animal (string newName) { name = NewName; } public void Feed () {   ; Console.WriteLine ("{0} has been fed", name); } public abstract void Makeanoise (); } #endregion复制代码复制代码//cow Animal subclasses to implement virtual methods & nbsp public class cow:animal { public Cow (string name): &NB Sp Base (name) { } public Overr IDE void makeAnoise () { Console.WriteLine ("{0} says ' Moo! '", name); } } Copy Code copy Code//chicken class, Animal subclass public class chicken:animal &N Bsp { public Chicken (string name) : Base (name) &NBSP ; {} public override void Makeanoise () { & nbsp Console.WriteLine ("{0} says ' Cluck '", name); } } Copy code copy code//cow Subclass, have a way of fly class supercow:cow { public Supercow (string name): Base (name) { } public void F Ly () { Console.WriteLine ("{0} is flying!", name);   ; &NBSp } public override void Makeanoise () { &NBS P Console.WriteLine ("{0} says ' I am supercow! '", name); } After the copy code class is ready, we can start defining our generics with the: copy code//inherited iterator interface, which makes it easy to use the foreach constraint with its type animal and its subclasses public class farm< t>:ienumerable<t> where t:animal { private list<t> animals = new List<t> (); public list<t> animals { & nbsp get { Return animals; } } //iterator &nbs P Public ienumerator<t> GetEnumerator () { return animals. GetEnumerator (); } IEnumerator Ienumerable.getenumerator () & nbsp { return animals. GetEnumerator (); } //execute all Animal makeanoise () & nbsp public void makenoises () { foreach (T animal in Animals) { animal. Makeanoise (); } } //execute all ANI Mal's feed () public void feedtheanimals () { foreach (T Animal in animals) { Animal. FeeD (); } } //get COW&N in animals Bsp Public farm<cow> getcows () { &NBSP ; farm<cow> cowfarm = new farm<cow> (); foreach (T Animal in animals) &NB Sp { if (animal is Cow) &NBSP ; { COWFARM.A Nimals. ADD (animal as Cow); } }&NB Sp return cowfarm; } } Copy the code generic definition OK, let's write the code to call it: Copy code class program { static void Main (string[] args) {&NBsp farm<animal> Farm = new farm<animal> (); & nbsp Farm. Animals.add (New Cow ("Jack")); Farm. Animals.add (New Chicken ("Vera")); Farm. Animals.add (New Chicken ("Sally")); Farm. Animals.add (New Supercow ("Kevin")); Farm. Makenoises (); farm<cow> dairyfarm = Farm. Getcows (); dairyfarm.feedtheanimals (); & nbsp foreach (Cow Cow in Dairyfarm) { if (cow is Supercow) { &NB Sp (cow as Supercow). Fly ();   } } Console. ReadKey (); } }
. NET-based custom generic