Start talking about C # generics and delegation (1)

Source: Internet
Author: User

In JAVA, generics are only supported by the JAVA compiler and are not supported by JVM. That is to say, no new bytecode is defined to indicate the generic type, naturally, there will be no new commands in the JVM to support new bytecode. Similar to. NET, it is supported by the C # compiler rather than the CLR. This creates a lot of interesting questions. We all know that our code must be translated and modified by the compiler. in JAVA, generics are implemented by the JAVA compiler in the form of Type erasure. All defined generic types automatically provide a corresponding raw type. The original type name is the generic name after the type parameter is deleted, and the type variable is erased, replace it with a limited type (Object is used for infinitely fixed variables). It can be regarded as a syntactic sugar. For example:

View sourceprint? Public class MyHashMap <TKey, TValue> {

Private HashMap <TKey, TValue> m_map = new HashMap <TKey, TValue> ();

Public TValue get (TKey key ){

Return this. m_map.get (key );

}

Public void put (TKey key, TValue value ){

This. m_map.put (key, value );

}

Public static void main (String [] args ){

MyHashMap <String, Integer> map = new MyHashMap <String, Integer> ();

Map. put ("Hello", 5 );

Int I = map. get ("Hello ");

}

}

 

After being compiled into bytecode, it looks like this (it is also represented by JAVA code)

Public class MyHashMap {private HashMap m_map = new HashMap (); public Object get (Object key) {return this. m_map.get (key);} public void put (Object key, Object value) {this. m_map.put (key, value);} public static void main (String [] args) {MyHashMap map = new MyHashMap (); map. put ("Hello", 5); int I = (Integer) map. get ("Hello") ;}} okay. When I see the Object, I admit that I think of packing again. We can see that the generic type in Java does not solve the packing problem.

Since JVM does not know the generic type, JAVA is represented in the form of the syntax sugar of the JAVA compiler. When I first came into contact with JAVA, I was indeed confused by the following errors.

View sourceprint? Public class MyClass <SomeType> {

Public static void myMethod (Object item ){

If (item instanceof SomeType) {// Error

...

}

SomeType st = new SomeType (); // Error

SomeType [] myArray = new SomeType [10]; // Error

}

}

 

 


Here we can think about how to truly support generics? In. NET, the CLR executes the IL code based on metadata, so it is easy to understand:

1. IL will certainly have a new command to identify "type parameters ".

2. We know that the definition of types and methods has a corresponding representation in the metadata table. To support generics, the metadata format will also be changed.

3. Modify the JIT compiler to execute new IL commands.

That is to say, the generic type definition can be fully compiled into the MSIL type.

 

The general process for running a generic type is as follows:

C # The Compiler generates IL and metadata, indicating generic class definitions. The JIT compiler combines generic type definitions with a series of type parameters.

Specifically, IL reserves a placeholder for initializing a generic instance. The JIT compiler will "complete the definition" when generating machine code during runtime ". JIT compiles the corresponding IL code into X86 commands and optimizes them at the same time. What has been optimized? For example, when the type parameter is a reference type, the same machine code can be used for representation. Why is it a reference type instead of a value type? Because the reference types are basically pointers, the structures are essentially the same.

Next, let's talk about class loading. JIT does not generate a complete X86 command for a class when it is loaded, but starts compilation only when every method in the class is called for the first time. (I think it is better to talk about the type, object, thread stack, and managed stack at runtime ). In this way, you will first execute a placeholder replacement step on the IL code, replace it with a specific type, and then compile as needed like a common class.


Well, you can see that the placeholder is replaced with a specific type before execution, so the wildcard matching degree is quite high. It should be said that it is exact matching. What will this affect? This will be reflected in method overloading. For an object derived from MyBase, WriteMEsaage <T> (T obj) takes precedence over WriteMEsaage (MyBase obj) in reload matching. Because the "exact match" can be completed by replacing T with MyDerived compiler, and WriteMEsaage (MyBase obj) requires an implicit conversion. Therefore, generic methods are more advantageous unless explicit type conversion is performed during the call. The following code is used:

View sourceprint? Public class MyBase

{

}

Public class MyDerived: MyBase

{

# Region IMessageWriter Members

Void IMessageWriter. WriteMessage ()

{

Console. WriteLine ("Inside MyDerived. WriteMessage ");

}

# Endregion

}

Class Program

{

Static void WriteMessage (MyBase B ){

Console. WriteLine ("Inside WriteMessage (MyBase )");

}

Static void WriteMessage <T> (T obj)

{

Console. Write ("Inside WriteMessage <T> (T ):");

Console. WriteLine (obj. ToString ());

}

Static void Main (string [] args)

{

MyDerived d = new MyDerived ();

Console. WriteLine ("Calling Program. WriteMessage ");

WriteMessage (d); // Let the compiler infer which matching method to use

Console. WriteLine ();

Console. WriteLine ("Cast to base object ");

WriteMessage (MyBase) d );

Console. WriteLine ();

}

}

 

Therefore, if you want to support a certain type and all its derived classes, creating generics based on the base classes is not the best choice. The same is true for interfaces.

In this case, we need to judge the problem through the runtime. Of course, this is not the best solution. Although it shields the caller from the specific implementation, but it also carries the runtime check overhead.

View sourceprint? Static void WriteMessage <T> (T obj ){

If (obje is MyBase ){

WriteMessage (obj as MyBase); // explicit type conversion

} Else {

Conslole. Write ("Invoke WriteMessage <T> ")

}

}

Related Article

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.