Dynamic class generation through emit

Source: Internet
Author: User
Tags class generator
Dynamic generation of a class is very helpful for technologies such as AOP and O/R Mapping. For Java, the problem is not big, but for. net, it is more troublesome (the main trouble lies in the implementation Code So I guess this may also be the reason why Java is a little ahead of the Way In AOP, O/R Mapping.

It is difficult to dynamically generate a simple class.

Assume that the following interfaces are available:
Interface ianimal
{
Void move ();
Void eat ();
}

You want to create a class generator typecreator and use it in the following ways:

Typecreator Tc = new typecreator (typeof (ianimal ));
Type T = tc. Build ();
Ianimal myanimal = (ianimal) activator. createinstance (t );
Myanimal. Move ();
Myanimal. Eat ();
First, we found that system. reflection. emit. typebuilder seems to be a ready-made class generator. However, typebuilder neither has a practical static method nor can it be instantiated externally. However, modulebuilder has a definetype () method to obtain typebuilder. While modulebuilder and typerbuilder have the same virtue and cannot be directly created. They must be obtained from the definedynamicmodule () method of assemblybuilder. Trace the source, assemblybuilder gets from the definedynamicassembly () of appdomain. In the end, appdomain provides a static method: appdomain. currentdomain. This series is not unreasonable. The type is attached to the module, while the module is attached to the Assembly, while the Assembly is loaded by the appdomain. In order to create the "Fur" of type, we must first construct the "skins" of assembly and module in sequence:

Using system;
Using system. reflection;
Using system. reflection. emit;

Public class typecreator
{
Private type targettype;

/// <Summary>
/// Constructor
/// </Summary>
/// <Param name = "targettype"> implemented or inherited type </param>
Public typecreator (type targettype)
{
This.tar GetType = targettype;
}

Public type build ()
{
// Obtain the current appdomain
Appdomain currentappdomain = appdomain. currentdomain;

// System. reflection. assemblyname indicates the complete name of an assembly.
Assemblyname assyname = new assemblyname ();

// Define a name for the Assembly to be created (the version number, culture, and other information are ignored here)
Assyname. Name = "myassyfor _" + targettype. Name;

// Obtain assemblybuilder
// Assemblybuilderaccess has three values: Run, save, and runandsave.
Assemblybuilder assybuilder = currentappdomain. definedynamicassembly (assyname, assemblybuilderaccess. Run );

// Obtain modulebuilder and provide the string parameter as the module name.
Modulebuilder modbuilder = assybuilder. definedynamicmodule ("mymodfor _" + targettype. Name );

// Name of the New Type: either
String newtypename = "IMP _" + targettype. Name;

// Attributes of the new type: the class to be created, instead of interface and abstract class, and public
Typeattributes newtypeattribute = typeattributes. Class | typeattributes. Public;

// Declare the parent type of the new type to be created
Type newtypeparent;

// Declare the interface to be implemented for the new type to be created
Type [] newtypeinterfaces;

// Perform different operations on whether the base type is an interface
If (targettype. isinterface)
{
Newtypeparent = NULL;
Newtypeinterfaces = new type [] {targettype };
}
Else
{
Newtypeparent = targettype;
Newtypeinterfaces = new type [0];
}

// Obtain the type generator.
Typebuilder = modbuilder. definetype (newtypename, newtypeattribute, newtypeparent, newtypeinterfaces );

// The following will be the new type declaration method: the new type should be override base type, so the virtual Method

// Obtain all methods of the base type
Methodinfo [] targetmethods = targettype. getmethods ();

// Traverse each method. Obtain the virtual method signature as a new method.
Foreach (methodinfo targetmethod in targetmethods)
{
// Just pick out the virtual Method
If (targetmethod. isvirtual)
{
// Obtain the parameter types of the method.
Parameterinfo [] paraminfo = targetmethod. getparameters ();
Type [] paramtype = new type [paraminfo. Length];
For (INT I = 0; I <paraminfo. length; I ++)
Paramtype [I] = paraminfo [I]. parametertype;

// Input the method signature to obtain the method generator.
Methodbuilder = typebuilder. definemethod (targetmethod. Name, methodattributes. Public | methodattributes. Virtual, targetmethod. returntype, paramtype );

// Method implementation is essential because the specific class is to be generated. The implementation of the method is produced through the emit il code.

// Obtain the Il generator.
Ilgenerator ilgen = methodbuilder. getilgenerator ();
// The following three rows are equivalent to: {console. writeln ("I'm" + targetmethod. Name + "ing ");}
Ilgen. emit (Opcodes. ldstr, "I'm" + targetmethod. Name + "ing ");
Ilgen. emit (Opcodes. Call, typeof (console). getmethod ("writeline", new type [] {typeof (string )}));
Ilgen. emit (Opcodes. Ret );
}
}
// Create and return
Return (typebuilder. createtype ());
}
}

Let's test it: using system;

Public class Tester
{
Public static void main (string [] ARGs)
{
Typecreator Tc = new typecreator (typeof (ianimal ));
Type T = tc. Build ();
Ianimal animal = (ianimal) activator. createinstance (t );
Animal. Move ();
Animal. Eat ();

Console. Read ();
}
}

Output: I'm moveingi'm eating. Conclusion: if it is used for AOP, emit can dynamically generate a decoration class. Compared with the remoting-based TP/RP method, it may be more efficient and can intercept the new operator. Disadvantage: Non-virtual methods cannot be intercepted. It is good to generate classes for o/R Mapping.

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.