Introduced
The last one has been dragged for 3 months, criticizing himself.
Through the previous article. We can take out compiled static data, such as method parameter information, through the mono reflection code. But the reality is: I need to run the data, is the user input and other external dynamic data.
Since it is dynamic, it is unknown. How do we get through the pre-injected code?
In fact, this is a question of thinking, below we have a detailed look under.
Implement a common notation
public static string GetPoint (int x, int y) { var value=x;}
Wow, that's so easy. In fact, dynamic acquisition and our normal write code is the same, we put the code to inject, generate a received variable on it. Just like the value above , and then pass it on to our own function.
two injection definition
Public classWeaveservice:attribute {} Public classWeaveaction:attribute {} Public classlog:weaveaction { Public Static voidOnactionbefore (MethodBase mbbase,Object[] args) { for(inti =0; I < args. Length; i++) {Console.WriteLine (string. Format ("{0} method, the {1} parameter is: {2}", Mbbase.name,i, Args[i])); } } }
Weaveservice Weaveaction 2 attribute is an injected marker that allows us to quickly locate in the injection finder.
Onactionbefore is our receive function, and ARG is the parameter at which the function runs.
Three weave function
This piece of code has been commented on in detail in the previous article and is not much described here.
public static void Weave (string[] assemblypath) {foreach (var item in assemblypath) { var assembly = assemblydefinition.readassembly (item); var types = assembly. MainModule.Types.Where (n = n.customattributes.any (y = y.attributetype.resolve (). Name = = "Weaveservice")); foreach (var type in types) {foreach (var method in type). Methods) {var attrs = method. Customattributes.where (y = y.attributetype.resolve (). Basetype.name = = "Weaveaction"); foreach (Var attr in attrs) {var resolve = attr. Attributetype.resolve (); var Ilprocessor = method. Body.getilprocessor (); var firstinstruction = IlProcessor.Body.Instructions.First (); var Onactionbefore = resolve. GEtmethods (). Single (n = = N.name = = "Onactionbefore"); var mfreference = assembly. Mainmodule.import (typeof (System.Reflection.MethodBase). GetMethod ("Getcurrentmethod")); Ilprocessor.insertbefore (Firstinstruction, Ilprocessor.create (Opcodes.call, mfreference)); Makearrayofarguments (method, Firstinstruction, Ilprocessor, 0, method. Parameters.count, assembly); Ilprocessor.insertbefore (Firstinstruction, Ilprocessor.create (Opcodes.call, Onactionbefore)); }}} if (types. Any ()) {assembly. Write (item); } } }
three makearrayofarguments function.
The function that gets the function parameter dynamically, the code has the detailed comment.
1 /// <summary>2 ///Building Function Parameters3 /// </summary>4 /// <param name= "method" >the method to inject</param>5 /// <param name= "Firstinstruction" >The first line of instructions in the function body Il_0000:nop</param>6 /// <param name= "Writer" >mono IL processing container</param>7 /// <param name= "firstargument" >default No. 0 parameter start</param>8 /// <param name= "ArgumentCount" >number of function parameters, static data can be obtained</param>9 /// <param name= "assembly" >the assembly to inject</param>Ten Public Static voidMakearrayofarguments (Methoddefinition method, instruction Firstinstruction, ilprocessor writer,intfirstargument, One intArgumentCount, assemblydefinition Assembly) A { - //The first parameter value of the instance function is this (the current instance object), so start at 1. - intThisshift = method. IsStatic?0:1; the - if(ArgumentCount >0) - { - //We first create an empty array with the original function parameters, equal length. +Writer. InsertBefore (Firstinstruction, writer. Create (OPCODES.LDC_I4, ArgumentCount-firstargument)); - //then instance the object array, assigning to the array we created + writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.newarr, AAssembly. Mainmodule.import (typeof(Object)))); at - //C # code Description - //object[] arr=new object[argumentcount-firstargument] - for(inti = firstargument; i < ArgumentCount; i++)//Traversal Parameters - { - varparameter =method. Parameters[i]; in - //copy a value on the stack to writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.dup)); + //The constant i-firstargument is stacked, and the array [i-firstargument] is the stuff. -Writer. InsertBefore (Firstinstruction, writer. Create (OPCODES.LDC_I4, I-firstargument)); the //Press the i + thisshift parameter stack. *Writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.ldarg, ( Short) (i +( thisshift) )); $ //boxing into an objectPanax Notoginseng toobject (assembly, firstinstruction, parameter. ParameterType, writer); - //Pressurestack to array arr[i] Assignment the writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.stelem_ref)); + A //C # code Description the //Arr[i]=value; + } - } $ Else $ { - writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.ldnull)); - } the } - Public Static voidToobject (assemblydefinition Assembly, instruction Firstinstruction, typereference Originaltype, ILProcessor Writer)Wuyi { the if(Originaltype.isvaluetype) - { Wu //normal value types for boxing operations - writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.box, Originaltype)); About } $ Else - { - if(Originaltype.isgenericparameter) - { A //Collection Boxing + writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.box, assembly. Mainmodule.import (Originaltype)); the } - $ } the}
Introduces the function of the next mono InsertBefore. This function inserts an instruction before an instruction. Take a picture.
We can see from the diagram that the first line of instruction is IL_0000:NOP. The first line is appended with the LDC.I4 2 instruction, and the second row we are still NOP before. Top
Four Business Preparation
I define a user class to inject, and then tag it.
[Weaveservice] public static class Usermanager { [Log] public static string getusername (int userId, string MemberID) { return "success"; } [Log] public static string GetPoint (int x, int y) { var sum = x + y; Return "User points:" + sum; } }
Our usual business notation does not require any extra action.
public static void Main (string[] args) { usermanager.getusername (1, "v123465"); Usermanager.getpoint (2, 3); Console.ReadLine (); }
Five injection calls
I typed the business class into the D drive and injected it with our previous function weave.
Codeinject.weave (newstring@ "D:\test\Test.exe" });
The operation results are as follows
Post-compilation C #
Summarize
Through static injection, we can better understand the Il language from the use.
Getting Dynamic Data is just a pick. With mono we can write our own AOP static components.
Reference Resources
1:postsharp Source
2:http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes_fields (v=vs.110). aspx
Mr. Mushroom
Source: http://www.cnblogs.com/mushroom/p/4124878.html
Reprint please keep the author and original address.
Log system Combat (ii)-AOP Dynamic acquisition of runtime data