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.