Why use C# generics?
In order to understand this problem, let’s look at the following code first. The code omits some content, but the function is to implement a stack. This stack can only handle int data types:
public class Stack PRivate int[] m_item; public int Pop(){...} public void Push(int item){...} public Stack(int i) { this.m_item = new int[i]; } } run That's great, but what should we do when we need a stack to save the string type? Many people will think of copying the above code and changing the int to string. Of course, there is nothing wrong with doing this in itself, but a good program will not do this because he thinks about what to do if he needs a long or Node type stack again in the future? Do you want to copy again? Excellent programmers will think of using a common data type object to implement this stack:
public class Stack { .} public Stack(int i) . But comprehensively speaking, it is not without flaws. The main manifestations are:
When Stack handles value types, boxing and folding operations will occur, which will allocate and recycle a large number of variables on the managed heap. If the amount of data is large, The performance loss is very serious.
When processing reference types, although there are no boxing and folding operations, the data type coercion operation will be used, which increases the burden on the processor.
There are more serious problems with data type coercion (assuming stack is an instance of Stack):
Node1 x = new Node1(); Pop(); The above code is completely fine when compiling, but because a Node1 type data is pushed, but it is required to be converted to Node2 type during Pop, this will cause a type conversion exception when the program is running, but it does not work. Escapes compiler checks.
To solve the problem of object type stack, we introduce generics, which can solve these problems elegantly. Generics use a passed data type T instead of object. The type of T is specified when the class is instantiated. The runtime (Runtime) automatically compiles into local code. The operating efficiency and code quality are greatly improved, and the data type is guaranteed. Safety.
Using C# generics
The following is to use generics to rewrite the above stack, using a common data type T as a placeholder, waiting to be replaced by an actual type during instantiation. Let's take a look at the power of generic:
Public class stack {Private T [] m_item; Public T POP () {...} Public Void Push (t item) {...} Public Stack (int i) { This.m_item = new T[i]; The writing method of the class remains unchanged. It just introduces the general data type T and it can be applied to any data type and is type safe. Calling method of this class:
//Instantiation can only save classes of type int Stack a = new Stack(100); a.Push(10); a.Push("8888"); //This line does not compile because class a only receives int Type of data int x = a.Pop(); //Instantiation can only save classes of string type Stack b = new Stack(100); b.Push(10); //This line does not compile because class b Only receives string type data b.Push("8888"); string y = b.Pop(); This class is completely different from the class implemented by object:
1. It is type safe. If a stack of type int is instantiated, data of type string cannot be processed, and the same is true for other data types.
2. No need to pack and fold boxes. When this class is instantiated, local code is generated according to the data type passed in. The local code data type has been determined, so there is no need for boxing and folding.
3. No type conversion required.
Theoretical knowledge:
The so-called generics: using parameterized types to operate multiple data types on the same code. Generic programming is a programming paradigm that uses "parameterized types" to abstract types to achieve more flexible reuse.
C# generics give the code stronger type safety, better reuse, higher efficiency, and clearer constraints.
C#'s generic capabilities are supported by the CLR at runtime, which is different from C++'s compile-time template mechanism and Java's compile-time "wiping method". This allows generic capabilities to interoperate seamlessly between CLR-enabled languages.
When C# generic code is compiled into IL and metadata, special placeholders are used to represent generic types, and proprietary IL instructions are used to support generic operations. The real generic instantiation work occurs in an "on-demand" manner during JIT compilation.
The C# generic compilation mechanism is as follows:
In the first round of compilation, the compiler only generates the "generic version" of IL code and metadata for the Stack type, and does not instantiate the generic type. T is only Acts as a placeholder.
During JIT compilation, when the JIT compiler encounters Stack for the first time, it will replace T in the "generic version" IL code and metadata with the int type -- to instantiate the generic type.
CLR generates the same code for all generic types whose type parameters are "reference types", but if the type parameters are "value types", CLR will generate a separate code for each different "value type" code.
Several features of C# generics
If the parameters of the instantiated generic type are the same, the JIT compiler will reuse the type, so C#'s dynamic generics capability avoids the code bloat problem that may be caused by C++ static templates .
C# generic types carry rich metadata, so C#'s generic types can be applied to powerful reflection technology.
C#’s generics use the constraint method of “base class, interface, constructor, value type/reference type” to implement “explicit constraints” on type parameters, which improves type safety while also losing the C++ template based on “ High flexibility of implicit constraints of "signature".
When a C# generic class is compiled, the intermediate code IL is first generated, and the general type T is just a placeholder. When instantiating a class, T is replaced by the data type specified by the user and the local code is generated by the just-in-time compiler (JIT). The actual data type has been used in this local code, which is equivalent to the class written with the actual type, so it is different The native code of a closed class is different. According to this principle, we can think of it this way: different closed classes of generic classes are different data types.
In this way, generics are not only more flexible, but also improve the simplicity and simplicity of the code to a new level! No more writing specific code for different overloaded methods!
C# Generics are an invaluable asset in the development tool arsenal. They improve performance, type safety, and quality, reduce repetitive programming tasks, and simplify the overall programming model, all through an elegant, readable syntax. Although the roots of C# generics are C++ templates, C# takes generics to the next level by providing compile-time safety and support. C# takes advantage of two-phase compilation, metadata, and innovative concepts such as constraints and general methods. There is no doubt that future versions of C# will continue to evolve generics in order to add new functionality and extend generics to other .NET Framework areas such as data access or localization.
That’s a brief talk about C# generics The useful content, please pay attention to the PHP Chinese website (www.php.cn) for more related content!