Emit advanced creation custom delegate

Source: Internet
Author: User
Tags emit

With the previous study on emit, we had a better understanding of msil and emit. However, to better implement AOP, we need to define the delegate by ourselves, but the definition Delegate of emit is not as easy to understand as the class, after comparing the Il code multiple times, the custom delegate is successfully implemented.

First, let's look at the general delegate definition method.

public delegate string MyDelegate(string message);

As defined by msdn, delegation is a data structure that references static methods, class instances, and class instance methods.

However, the essence of delegation is a class automatically generated by the system. Let's first look at the structure of mydelegate in Il.

We can see that mydelegate is actually a class inherited from multicastdelegate.

The msil format is as follows:

.class public auto ansi sealed EmitDemo.DelegateDemo.MyDelegate
extends [mscorlib]System.MulticastDelegate
{
} // end of class EmitDemo.DelegateDemo.MyDelegate


.method public hidebysig specialname rtspecialname
instance void .ctor(object 'object',
native int 'method') runtime managed
{
} // end of method MyDelegate::.ctor

.method public hidebysig newslot virtual
instance string Invoke(string message) runtime managed
{
} // end of method MyDelegate::Invoke

 

Asynchronous calling is not considered. The actual class is like this representation, but C # does not allow direct inheritance of multicastdelegate, so compilation fails.

public class MyDelegate:MulticastDelegate
{
public MyDelegate(object target,IntPtr method)
:base(target,method)
{

}

public override string Invoke(string message){}
}

Next, follow this definition to implement the delegate class.

First, modulebuilder should be familiar with emit.

           string name = "MyDelegateDemo";
string fileName = name + ".dll";
var assemblyName = new AssemblyName(name);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,
AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, fileName);

The next step is to define the class. The key point is that the modified parameters must be consistent, and the base class is multicastdelegate.

 //public auto ansi sealed
var delegateBuilder = moduleBuilder.DefineType("MyDelegate",
TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.AnsiClass |
TypeAttributes.Sealed, typeof(MulticastDelegate));

When you set the constructor, the modification parameters must be consistent. The function parameters are object and intptr.

The most important thing is to set the method implementation flag as runtime.

  //            .method public hidebysig specialname rtspecialname 
// instance void .ctor(object 'object',
// native int 'method') runtime managed
//{
//} // end of method MyDelegate::.ctor

var constructorBuilder = delegateBuilder.DefineConstructor(
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName,
CallingConventions.Standard, new[] { typeof(object), typeof(IntPtr) }
);
constructorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime);

Then, define the method invoke. The returned values and parameters defined here are strings that can be adjusted as needed.

The modification must be consistent, and the method implementation flag must be set to runtime.

 //            .method public hidebysig newslot virtual 
// instance string Invoke(string message) runtime managed
//{
//} // end of method MyDelegate::Invoke
var resultType = typeof(string);
var paramTypes = new[] { typeof(string) };
var methodBuilder = delegateBuilder.DefineMethod("Invoke",
MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot |
MethodAttributes.Virtual,
CallingConventions.Standard, resultType, paramTypes);
methodBuilder.SetImplementationFlags(MethodImplAttributes.Runtime);

 

Finally, the type is created. Now, the definition is complete.

var delegateType = delegateBuilder.CreateType();

Next we need to call the test.

Note that you cannot use activator. createinstance () to initialize the proxy but delegate. createdelegate.

public class MyClass
{

public string MyMethod(string message)
{
Console.WriteLine(message);
return message;
}

}

 

Call

 MyClass myClass = new MyClass();
var myDelegate = Delegate.CreateDelegate(delegateType, myClass, "MyMethod");
myDelegate.DynamicInvoke("Hello World!");

Result: Hello world!

OK.

 

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.