Emit Learning (2), emit Learning
In the previous article, the object creation process is not introduced. This article mainly introduces the object creation process.
After you are familiar with the IL syntax, you can use Reflector to decompile the code to view it. Because of this tool, you can compare the IL code in Reflecotr to write the IL of Emit.
Now, start with the question, or start with the instance:
I. Example
First, create a class (Person, Contacts ):
public class Person { public string Name { get; set; } public int Age { get; set; } public Contacts Contact { get; set; } public override string ToString() { return string.Format("Name:{0}\r\nAge:{1}\r\nContact:{2}", this.Name, this.Age, this.Contact.ToString()); } } public class Contacts { public string Address { get; set; } public string Phone { get; set; } public string QQ { get; set; } public override string ToString() { var res = string.Format(@"[Address:{0}, Phone:{1}, QQ:{2}]", this.Address, this.Phone, this.QQ); return res; } }
Then you can write the creation method:
static void PersonTest(){ var contacts = new Contacts { Address="HeFei", Phone="15112341234", QQ="66666666"}; var person = new Person { Name = "Wubi", Age = 20, Contact = contacts }; Console.WriteLine(person.ToString()); }
The decompiled IL code is as follows:
.method private hidebysig static void PersonTest() cil managed{ .maxstack 2 .locals init ( [0] class ConsoleApplication1.Contacts contacts, [1] class ConsoleApplication1.Person person, [2] class ConsoleApplication1.Contacts contacts2, [3] class ConsoleApplication1.Person person2) L_0000: nop L_0001: newobj instance void ConsoleApplication1.Contacts::.ctor() L_0006: stloc.2 L_0007: ldloc.2 L_0008: ldstr "HeFei" L_000d: callvirt instance void ConsoleApplication1.Contacts::set_Address(string) //contacts2.Address = "HeFei" L_0012: nop L_0013: ldloc.2 L_0014: ldstr "15112341234" L_0019: callvirt instance void ConsoleApplication1.Contacts::set_Phone(string) L_001e: nop L_001f: ldloc.2 L_0020: ldstr "66666666" L_0025: callvirt instance void ConsoleApplication1.Contacts::set_QQ(string) L_002a: nop L_002b: ldloc.2 L_002c: stloc.0 //contacts = contacts2 L_002d: newobj instance void ConsoleApplication1.Person::.ctor() L_0032: stloc.3 L_0033: ldloc.3 L_0034: ldstr "Wubi" L_0039: callvirt instance void ConsoleApplication1.Person::set_Name(string) L_003e: nop L_003f: ldloc.3 L_0040: ldc.i4.s 20 L_0042: callvirt instance void ConsoleApplication1.Person::set_Age(int32) L_0047: nop L_0048: ldloc.3 L_0049: ldloc.0 L_004a: callvirt instance void ConsoleApplication1.Person::set_Contact(class ConsoleApplication1.Contacts) L_004f: nop L_0050: ldloc.3 L_0051: stloc.1 L_0052: ldloc.1 L_0053: callvirt instance string [mscorlib]System.Object::ToString() L_0058: call void [mscorlib]System.Console::WriteLine(string) L_005d: nop L_005e: ret }
Ii. supplementary points
Some people may have noticed that calling a method here is not a Call, but a Callvirt. When is a Call and a Callvirt?
First of all, we can see the location where callvirt appears. In public string Name {get; set;}, get and set are actually two methods. We all know that, therefore, when assigning values to attributes, it is actually a call method. Therefore, the assignment here is not based on stloc.
. Method public hidebysig specialname instance void set_Name (string 'value') cel managed {. custom instance void [mscorlib] System. runtime. compilerServices. compilerGeneratedAttribute ::. ctor (). in maxstack 8 L_0000: ldarg.0 // non-static method, arg0 indicates this L_0001: ldarg.1 // arg1 is the 'value' L_0002: stfld string leleapplication1.person :: <Name> k _ BackingField L_0007: ret}
Next, let's look at the two commands literally.
Call means Call. What does Callvirt mean? From the previous experience, I thought that these commands are not random and short to a letter are of specific significance. Therefore, we split Callvirt and only look at virt, is it a bit familiar with the catch-up, compared with the word virtual, you can understand that Callvirt is mainly to call those methods.
Hey, no more. The following are some differences between call and callvirt:
1. call can call static methods, instance methods, and virtual methods. While callvirt can only call instance methods and virtual methods. It is insufficient for static methods.
2. call calls a function in a non-virtual way, while callvirt calls the function in a multi-state manner.
As for the similarities and differences of the instance, I will not give, you can take a look: http://www.cnblogs.com/wang_yb/archive/2011/06/28/2092327.html
The Internet era is good. It's easy to get the results of others. Thank you guys.