Dynamic class generation through EMIT

xiaoxiao2021-03-06  60

Dynamically generates a class that is very helpful for AOP, O / R mapping. For Java, the problem is not big, and for .NET, it is troublesome (the main trouble is to achieve the code generation requires IL), so speculation may also be in AOP, O / R mapping, Java is slightly Reason.

Trouble is troublesome, non-can't, dynamically generate a simple class is not too difficult.

It is assumed that there is an interface: interface ianimal {void (); void Eat ();} I hope to create a class generator TypeCreator and can be used in the following ways:

TYPECREATOR TC = New TypeCreat (TypeOf (IANIMAL));

TYPE T = tc.build ();

Ianimal myanimal = (ianimal) Activator.createInstance (T);

Myanimal.move ();

Myanimal.eat ();

First, find System.Reflection.Emit.TyPeBuilder seems to be an off-the-shelf generator. However, Typebuilder has neither practical STITIC method and cannot be instantiated outside. However, ModuleBuilder has a defineType () method, you can get TypeBuilder; and ModuleBuilder and Typerbuilder virtue, you can't create it directly, you can get it from the definedynamicModule () method of AssemblyBuilder. Chasing the source, AssemblyBuilder has to come from Appdomain's definedynamicassembly (). Finally, it is good to provide a static method: appdomain.currentdomain. This series is not reasonable, the type is attached to Module, and Module is attached to Assembly, while Assembly is loaded by Appdomain. The so-called "skin of the skin is attached", in order to create Type "Mao", first construct Assembly, Module these "skin":

Using system;

Using system.reflection;

Using system.reflection.emit;

Public Class Typecreator

{

Private type targettype;

///

/// Constructor

///

// / Type of implementation or inheritance

Public Typecreator (Type Targettype)

{

THIS.TARGETTYPE = TargetType;

}

Public type build ()

{

// Get the current Appdomain

Appdomain currentAppdomain = appdomain.currentdomain

//System.reflection.AssemblyName is used to represent a full name of an assemblyMbly

AskMBLYNAME ASSYNAME = New assemblyname ();

/ / Define a name for Assembly to create (ignore the version number, Culture and other information)

Assyname.name = "Myassyfor_" TargetType.Name;

/ / Get assemblybuilder

// assemblybuilderccess has Run, Save, Runandsave three values

AssemblyBuilder Assybuilder = CurrentAppdomain.defineDynamicassembly (Assyname, AssemblyBuilderaCcess.run);

/ / Get ModuleBuilder, provide the string parameter as the Module name, casually set one

ModuleBuilder Modbuilder = Assybuilder.defineDynamicModule ("MyModfor _" TargetType.Name);

// New type name: casually one

String newTypename = "IMP _" Targettype.Name;

// New type properties: To create a Class, not Interface, Abstract Class, etc., and is public

TypeAttributes newtypettribute = typettributes.class | typettributes.public;

// State out the new type of parent type to create

TYPE NewTypeParent;

// State out the interface to be created to be implemented

TYPE [] NewTypeInterface;

/ / Do not have interfaces for the base type, do different processing

IF (targettype.isinterface)

{

NewtypeParent = NULL;

NewTypeInterfaces = new type [] {targettype};

}

Else

{

NEWTYPANT = TargetType;

NewTypeInterfaces = new type [0];

}

// Get the type generator

Typebuilder Typebuilder = Modbuilder.defineType (NewTypeName, NewTyPeattribute, NewTyParent, NewTypeInterface);

// The following will declare method for new types: New type should override base type, so Virtual method

// Get all methods of the base type

MethodInfo [] TargetMethods = targettype.getMethods ();

// Traverse each method, to obtain the signature for Virtual, as a new type of method

Foreach (MethodInfo TargetMethod in TargetMethods)

{

// only pick the way of Virtual

IF (targetMethod.isvirtual)

{

// Get the type of each parameter of the method

ParameterInfo [] paraminfo = targetMethod.getParameters ();

TYPE [] paramtype = new type [paraminfo.length];

For (int i = 0; i

/ / Incoming method signature, get method generator

MethodBuilder Methodbuilder = Typebuilder.defineMethod (TargetMethod.Name, Methodattributes.Public | MethodAttributes.Virtual, TargetMethod.Returntype, paramtype);

// The implementation of the method is essential because the specific class to be generated is essential. The method of the method is generated by the Emit IL code.

// Get the IL generator

Ilgenerator ilgen = methodbuilder.getilgenerator ();

// The following three lines 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);

}

}

/ / Really create, and return

Return (Typebuilder.createType ());

}

}

Ok, try it to see: use system;

Public Class Tester

{

Public static void main (string [] args)

{

TYPECREATOR TC = New TypeCreat (TypeOf (IANIMAL));

TYPE T = tc.build ();

IANIMAL Animal = (iAnimal) Activator.createInstance (T);

Animal.move ();

Animal.eat ();

Console.read ();

}

}

Get the output: I'm moveingi'm Eating summary: If used for AOP, EMIT can dynamically generate a decorative class, compared to the REMOTING-based TP / RP method, efficiency may be higher, and can also intercept construct function. Disadvantages: For non-Virtual methods, it seems that it cannot be intercepted. The class generated for o / r mapping, it is good

转载请注明原文地址:https://www.9cbs.com/read-118894.html

New Post(0)