In-depth understanding of C # generics

Source: Internet
Author: User
Tags mscorlib

The first two articles describe the basic knowledge and features of C # generics, and let's look at how generics work, and learn about generics inside mechanisms.

Generic internal mechanisms

Generics have type parameters that provide a "parameterized" type through the type parameter, in fact, the type parameter of the generic type becomes the metadata of the generic type, and the runtime uses them to construct the appropriate type, through which we have the ability to instantiate different types of objects. That is, unbound generic types are blueprints for constructing generic types, and constructed generic types are blueprints of actual objects.

Parsing generic IL code

Here is an example where you define a generic class for comparison and a non-generic class that compares int:

namespacegenerictest{classCompareutil<t>wheret:icomparable { PublicT ItemOne {Get;Set; }  PublicT Itemtwo {Get;Set; }  Publiccompareutil (t ItemOne, T itemtwo) { This. ItemOne =ItemOne;  This. Itemtwo =Itemtwo; }         PublicT Getbiggerone () {if(Itemone.compareto (Itemtwo) >0)            {                returnItemOne; }            returnItemtwo; }    }    classIntcompareutil { Public intItemOne {Get;Set; }  Public intItemtwo {Get;Set; }  PublicIntcompareutil (intItemOne,intitemtwo) {             This. ItemOne =ItemOne;  This. Itemtwo =Itemtwo; }         Public intGetbiggerone () {if(Itemone.compareto (Itemtwo) >0)            {                returnItemOne; }            returnItemtwo; }    }    classProgram {Static voidMain (string[] args) {Compareutil<int> compareint =Newcompareutil<int> (3,6); intBigInt =Compareint.getbiggerone (); Intcompareutil Intcompareutil=NewIntcompareutil (4,7); intBig =Intcompareutil.getbiggerone ();        Console.read (); }    }} 

First, take a look at the IL code for the generic class "Compareutil<t>" (only part of the IL Code is listed) by Ilspy

. Class Private Auto ANSI beforefieldinitGenerictest.compareutil '1< ([mscorlib]system.icomparable) t>extends[mscorlib]system.object{ .... Method  Public Hidebysig specialname rtspecialname         instance void. ctor (! T ItemOne,! T itemtwo)CIL managed{...} ...//Properties. propertyinstance ! T ItemOne () {. Getinstance!0Generictest.compareutil '1:: Get_itemone (). Setinstance voidGenerictest.compareutil '1:: Set_itemone (!0)}. Propertyinstance ! T Itemtwo () {. Getinstance!0Generictest.compareutil '1:: Get_itemtwo (). Setinstance voidGenerictest.compareutil '1:: Set_itemtwo (!0)    }} //end of Class Generictest.compareutil ' 1

You can see the IL code of the non-generic class "Intcompareutil", and you will find that the IL code of the generic class is basically the same as the IL Code of the non-generic class, except that some type parameter metadata is more in the IL Code of the generic class .

Let's look at a few special points in the generic class IL code:

    • Generictest.compareutil ' 1< ([mscorlib]system.icomparable) t>
      • ' 1 represents the number of tuples, which is the quantity of the type parameter
      • < ([mscorlib]system.icomparable) t> is the type constraint we add on a generic type
    • ! T and!0
      • ! T is a placeholder for the type parameter
      • ! 0 represents the first type parameter (when the number of the generic is 2 o'clock,!1 represents the second type parameter)

You can also compare instances of generic classes and non-generic classes to construct IL code

il_0003: newobj instance void class Generictest.compareutil '1<int32>::.ctor (!  0,! 0 )il_0012:newobjinstancevoid generictest.intcompareutil::. ctor (int32int32)
Generic mechanism

As you can get from the above analysis, C # generics have CLR support at runtime, and the compiler does two things when dealing with generics:

    1. When the compiler encounters a generic code such as "Compareutil<t>", the compiler compiles generic code into IL Code and metadata, using special placeholders to represent type parameters
    2. While a true generic instantiation works in a "on-demand" manner, that is, when the compiler encounters code that "compareutil<int> compareint" specifies the type argument, the Il of the generic type is converted to the cost machine code based on the type argument JIT, The actual data type is already used in this native code, equivalent to the class declared with the actual type
Instantiation of value types and reference types

JIT produces the same copy of native code for all generic types with a type parameter of reference type, because all references have the same size.

However, if the type parameter is value type, for each of the different value types, the JIT produces a separate native code for it.

As for why using generic classes, you can avoid boxing and unboxing of value types:

list<intnew list<int> ();

I believe you see that the following IL code is clear, in the generic class, the type parameter is used directly by the value type.

//  Fields . Field Private ! T[] _items
Using typeof for generic types

In C #, we often use the TypeOf operator to obtain a reference to a System.Type object.

For generic types, we can also use typeof in two ways:

    • Get generic type definition (unbound generic type)
      • To get the definition of a generic type, you only need to provide the declared type name, delete all type arguments, but leave the comma
    • Gets the specific constructed type (that is, the type reference that gets the enclosing type)
      • Only the type argument needs to be specified

Let's look at a simple example,

Static voidDemonstratetypeof<t>() {Console.WriteLine (typeof(T)); Console.WriteLine (typeof(list<>)); Console.WriteLine (typeof(dictionary<,>)); Console.WriteLine (typeof(list<t>)); Console.WriteLine (typeof(dictionary<string, t>)); Console.WriteLine (typeof(list<Long>)); Console.WriteLine (typeof(dictionary<string,int>));}

The output of the function is as follows:

System.DoubleSystem.Collections.Generic.List ' 1 [t]system.collections.generic.dictionary ' 2 [tkey,tvalue]system.collections.generic.list ' 1 [system.double]system.collections.generic.dictionary ' 2 [system.string,system.double]system.collections.generic.list ' 1 [system.int64]system.collections.generic.dictionary ' 2 [System.string,system.int32]

With the result of the output, we can also see the number of tuples for each generic type, as well as the types of generic types (unbound generic types and enclosing types).

Static fields and static constructors in generic fields

In C #, static member variables of a class are shared among different class instances and can be accessed through the class name. The introduction of generics in C # 2.0 led to some changes in the mechanism of static member variables: static member variables are shared between the same enclosing type, and not shared between different enclosing types . This is also very easy to understand, because different enclosing types have the same class name, but because they pass in different data types separately, they are completely different types.

See a simple example:

namespacegenerictest{classTypewithfield<t>    {         Public Static stringfield;  Public Static voidPrintfield () {Console.WriteLine (field); }    }    classProgram {Static voidMain (string[] args) {Typewithfield<int>.field ="Int Field"; Typewithfield<string>.field ="String Field"; Typewithfield<int>.            Printfield (); Typewithfield<string>.            Printfield ();        Console.read (); }    }} 
Static constructors in generics

Static constructor rules: There can only be one, and cannot have parameters, he can only be. NET runtime is called automatically, and cannot be called manually, and can only be performed once.

The principle of static constructors in generics is the same as for non-generic classes, simply by understanding the different enclosing classes in generics as different classes.

Summarize

This article introduces the working mechanism of generics and the further understanding of generics. At the same time, combined with the working principle of generics, you see why a value type using generics avoids boxing and unpacking.

In-depth understanding of C # generics

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.