30-minute Generic tutorial

Source: Internet
Author: User

First, the introduction of generics:

Let's take a look at one of the most common definitions of generic type list<t>
(The real definition is much more complicated than this, I have deleted a lot of things here)

[Serializable]public class list<t>: Ilist<t>, Icollection<t>, ienumerable<t>{public    T This[int index] {get; set;}    public void Add (T item);    public void Clear ();    public bool Contains (T item);    public int IndexOf (T item);    public bool Remove (T item);    public void Sort ();    Public t[] ToArray ();}

The list is followed by a <T> indicating that it operates on an unspecified data type
(t represents a data type that is not specified)

You can think of T as a variable name, T represents a type,
You can use T anywhere in the source code of List<t>

T is used as the parameter and return value of the method
The Add method receives a parameter of type T, and the ToArray method returns an array of type T

Attention:

Generic parameters should start with T, or call T, or call TKey, TValue, and so on;
This is the same as the interface to start with I, which is the Convention.

Here's a look at the code that uses a generic type

            var a = new list<int> ();            A.add (1);            A.add (2);            This is wrong, because you have specified a generic type of int, you can not put other values in this container            //This is a compiler error, but also improve the efficiency of troubleshooting, if it is a run-time error, do not know how annoying            a.add ("3");            var item = a[2];

Please note that the comments in the above code

Second, the role of generics (1):

As a programmer, write code at all times without forgetting code reuse.
Code reuse can be divided into classes, where algorithmic reuse is a very important category

Suppose you want to write a sort algorithm for a set of integer data and write a sort algorithm for a set of floating-point data
What would you do if you didn't have a generic type?

You may have thought of the overloaded method
Write two methods with the same name, one method receives an array of integers, and another method receives an array of floating-point types

But with generics, you don't have to do this at all, as long as you design a method that's enough, you can even sort a set of string data in this way

Third, the role of Generics (2):

Suppose you are the designer of a method,
This method needs to have an input parameter, but you can determine the type of the input parameter
So what are you going to do about it?

Some people may immediately refute: "There can be no such time!" ”
Well, I'll tell you, programming is an experiential job, and your experience isn't enough, and you haven't met a similar place.

Other people may consider setting the type of this parameter to object.
This is really a viable solution.
But it will cause the following two questions

If I pass the shaping data to this method,
(Data of value type is the same)
will result in additional packing and unpacking operations.
resulting in performance loss

If your processing logic in this method does not apply to the arguments of the string
And the user passes a string in.
The compiler is not going to error,
The error will only occur at run time.
(If the quality Control department does not detect this run-time bug, then do not know how much damage to do?)
That's what we always say: type insecurity

Iv. Examples of generics:

Generic types like list<t> and dictionary<tkey,tvalue> we often use
Here I introduce a few generic types that are not commonly used

Observablecollection<t>
When this set changes, there will be a corresponding event to be notified.
Take a look at the following code:

static void Main (string[] args) {    var a = new observablecollection<int> ();    A.collectionchanged + = a_collectionchanged;} static void A_collectionchanged (object sender, NotifyCollectionChangedEventArgs e) {    //You can use action to determine what action triggered the event    //e.action = = Notifycollectionchangedaction.add    //Can be based on the following two properties to get the content before and after the change    //e.newitems;    e.OldItems;}

Use this collection to refer to the following two namespaces

Using system.collections.objectmodel;using System.Collections.Specialized;

Blockingcollection<int> is a thread-safe collection
Take a look at the following code

var Bcollec = new blockingcollection<int> (2);//attempt to add 1-50task.run (() =>{    //Parallel Loop    parallel.for (1, wuyi, i = >    {        bcollec. ADD (i);        Console.WriteLine ("Add:" + i);    }); Thread.Sleep (1000); Console.WriteLine ("Call once Take"); Bcollec. Take ();//wait Indefinitely long time thread.sleep (Timeout.infinite);

The output is:

Join: 1 Join: 37 Call once take join: 13

Blockingcollection<int> can also set completeadding and IsCompleted properties to deny adding new elements
. NET class Library also provides a lot of generic types, here are not one by one examples of

V. Inheritance of generics:

Everything in. NET inherits from Object
Generics are no exception
Generic types can inherit from other types
Consider the following code

public class Mytype{Public    virtual String getonestr ()    {        return "base Object Str";    }} public class Myothertype<t>: mytype{public    override string Getonestr ()    {        return typeof (T). ToString ();    }} Class program{    static void Main (string[] args)    {        MyType target = new myothertype<int> ();        Console.WriteLine (Target.getonestr ());        Console.readkey ();    }}

Generic type myothertype<t> succeeded in overriding the method of non-generic type MyType
If I try to derive a subtype from a myothertype<t> type as follows, it will cause a compiler error

Compile-time error public class mythirdtype:myothertype<t>{}

But if it's written this way, it won't go wrong.

    public class mythirdtype:myothertype<int>    {public        override string Getonestr ()        {            return ' Mythirdtype ";        }    }

If a method receives a parameter of type Mythirdtype,
Then you cannot pass an instance of Myothertype<int> to this method
However a method if the parameter of the myothertype<int> type is received
It is possible to pass an instance of the Mythirdtype type to this method
It doesn't make a mistake to write the following way

    public class Mythirdtype<t>: myothertype<t>    {public        override string Getonestr ()        {            Return typeof (T). ToString () + "from Mythirdtype";        }    }

The trick in this, imaginative achievement here, inexpressible

VI. Generic interface

. NET class library has a lot of generic interfaces
such as:ienumerator<t>, ilist<t>, etc.
These interfaces are not described in detail here.
The value says why there should be a generic interface.

In fact, the cause of the generic interface is similar to the occurrence of generics
Take IComparable This interface,
This interface describes only one method:

int CompareTo (object obj);

As you can see, if it is a value type parameter, it is bound to result in boxing and unpacking operations
At the same time, it is not strongly typed and cannot be determined at compile time for the type of the parameter
With icomparable<t>, we can solve this problem.

int CompareTo (T other);

Vii. Generic Commission

Delegate Description method,
Generic delegates are similar in origin to generic interfaces

Defining a generic delegate is also relatively straightforward:

public delegate void myaction<t> (T obj);

This delegate describes a class of methods
Such methods receive parameters of type T, and no return value
Let's take a look at the method of using this delegate

public delegate void myaction<t> (T obj), static void Main (string[] args) {    var method = new Myaction<int> (p Rintint);    Method (3);    Console.readkey ();} static void Printint (int i) {    Console.WriteLine (i);}

Because defining delegates is cumbersome
. NET class library defines three more commonly used generic delegates under the system name space

Predicate<t> Commission:

Public delegate bool Predicate<t> (T obj);

This delegate describes the method to receive a parameter of type T, returning a value of type bool, which is generally used for comparison methods

Action<t> delegate

public delegate void action<t> (T obj);
public delegate void Action<t1, t2> (T1 arg1, T2 arg2);

This delegate describes the method that receives one or more parameters of type T (up to 16, I write only two types of definitions here), no return value

Func<t> delegate

Public delegate TResult func<tresult> ();
Public delegate TResult Func<t, tresult> (T Arg);

This delegate describes the method that receives 0 or more parameters of type T (up to 16, I write only two types of definitions here),
Unlike the action delegate, it has a return value with the type of the return value of type TResult.

For a description of the delegate, you can also read my article
30-Minute LINQ tutorial

Viii. generic methods

T in a generic type can be used anywhere in this type
However, there are times when we don't want to specify the type of T when we use the type.
We want to specify the type of T when using this type of method
Take a look at the following code:

    public class MyClass    {public        Tparam compareto<tparam> (Tparam Other)        {            Console.WriteLine ( Other. ToString ());            return to other;        }    }

MyClass is not a generic type in the code above
But compareto<tparam> () in this type is a generic method
Tparam can be used anywhere in this method.

Using generic methods is generally the following code:

Obj.compareto<int> (4);obj.compareto<string> ("ddd");

However, you can write it in a simpler way, written as follows

Obj.compareto (2); Obj.compareto ("123");

Some people will ask: "This is not possible, do not specify the CompareTo method of the Tparam type, will certainly compile the error"
I tell you: No, the compiler can help you do the type inference work.

Attention:
If you specify two generic parameters for a method, and both of these parameters are of type T,
So if you want to use type inference, you have to pass two parameters of the same type to this method
You cannot have one argument with the string type, and the other with the object type, which causes a compilation error.

IX. generic constraints

We have designed a generic type
Many times, we don't want the user to pass in any type of argument
In other words, we want to "constrain" the type of T
Take a look at the following code:

    public class myclass<t> where t:icomparable<t>    {public        int CompareTo (T other)        {            return 0;        }    }

The above code requires that the T type must implement the Icomparable<t> interface
As you can see: The constraints of generics are implemented by the keyword where.

Generic methods can of course also constrain generic parameters in a similar way
Take a look at the following code:

public class myclass{Public    tparam compareto<tparam> (Tparam other) where Tparam:class    {        Console.WriteLine (Other. ToString ());        return to other;    }}

The above code uses the class keyword to constrain the generic parameter tparam, which is explained later.

Note 1:
If I have a type that is also defined as myclass<t> but does not have a constraint,
then this time, the myclass<t> that did the constraint will be the MyClass <T> conflicts, compilation fails

Note 2:

When you override a generic method, if the method specifies a constraint
override this method, you can no longer specify a constraint

Note 3:

Although my example above is an interface constraint, you can write a type, such as BaseClass
and, as long as the type that inherits from BaseClass can be used as a T type, you do not try to constrain t to object type, the compilation will not pass. (That's what fools do)

Note 4:

has two special constraints: class and struct.
where t:class   constraint T type must be a reference type
where t:struct   constraint T type must be a value type

Note 5:
If you do not have a class constraint on T,
then you cannot write this code: t obj = null;   This cannot be compiled because T is likely to be of value type.
If you do not have a struct constraint on t and you do not have a new constraint on T
then you cannot write this code: T obj = new T ();   This cannot be compiled because value types must have parameterless constructors, and reference types are not necessarily.
If you have a new constraint on T: where T:new ();   then new T () is correct, because the new constraint requires the T type to have a public parameterless constructor.

Note 6:
There is also a way to handle the problem of value types and reference types
T temp = default (t), even if no constraints are made on T;
If T is a reference type, then temp is null, and if T is a value type, then temp is 0;

Note 7:
An attempt was made to cast a variable of type T, which would normally be reported as a compile-time error.
But you can first convert T to object and then convert object to the type you want (generally not recommended, you should consider converting T to a constraint-compatible type)
You can also consider type conversions with the as operator, which generally does not error, but can only be converted to a reference type.

As for the content of generic constraints, I have also mentioned in this article
30-Minute LINQ tutorial

X. contravariance and covariance

In general, when we use generics, the generic type marked by T is not changed
In other words, the following two ways of writing are wrong

var a = new list<object> (); List<string> b = A;var c = new list<string> (); List<object> d = c;

Note: There is no write-cast, even if the cast is wrong, the compilation cannot be passed

Generics, however, provide the properties of contravariance and covariance,
With both of these features, this conversion becomes possible.

Inversion:
A generic type T can be changed from a base type to a derived type of that class.
The type parameter of the contravariant form is marked with the IN keyword,
And this parameter is generally used as input parameter.

Co-change:
A generic type T can be changed from a derived type to its base type.
Use the Out keyword to mark the type parameter of the HKJA variable form,
And this parameter is generally used as the return value

If we define a delegate like this:

Public delegate TResult Myaction<in t,out tresult> (T obj);

Then, you can make the following code compile (without casting)

var a = new Myaction<object, argumentexception> (o = = new ArgumentException (o.tostring ())); myaction<string, exception> b = A;

This is the power of contravariance and covariance.

Attention:
Only generic types of interfaces and delegates can use the properties of contravariance and covariant

Resources

MGen's Blog
CLR VIA C # (third edition)

To modify a record:

Half of the content was completed in 2013.4.21

2013.4.28 completed the whole content, modified some typos

2013.4.29 added a lot of content, modified the layout style

A typo was modified in 2013.5.3, adding to the attention of contravariance and covariance.

2013.5.5 modified the "Attention" link in the integration section of generics

2013.5.6 modified generic Naming conventions the wording there

30-minute Generic tutorial

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.