Catalogue
One: Common wording
Two: injection definition
Three: Weave function
Four: Parameter construction
Five: Business Preparation
Six: Inject call
One: Common wording
1234 |
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 class Weaveservice:attribute { } public class Weaveaction:attribute { } public class Log:weaveaction {public static void Onactionbefore (MethodBase mbbase, object[] args) {for (int i = 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.
12345678910111213141516171819202122232425262728293031323334 |
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);
}
}
}
|
Four: Parameter construction
The function that gets the function parameter dynamically, the code has the detailed comment.
1//<summary> 2///Build function Parameters 3///</summary> 4//<param Name= "method" > to inject Method </param> 5//<param name= "firstinstruction" > function body the first line of instructions recognized il_0000:nop</param> 6///& Lt;param name= "Writer" >mono il processing container </param> 7//<param name= "firstargument" > Default No. 0 parameter start </param> ; 8//<param name= "ArgumentCount" > The number of function parameters, static data can be obtained </param> 9//<param name= "assembly" > Assembly to inject </param>10 public static void Makearrayofarguments (Methoddefinition method, instruction Firstinstruct Ion, ilprocessor writer, int firstargument,11 int argumentcount, assemblydefinit Ion assembly) 12 {13///instance function The first parameter value is this (the current instance object), so start with 1. int Thisshift = method. IsStatic? 0:1;15 if (ArgumentCount > 0) 17 {18//We first create an empty array with the original function parameters, equal length. Writer. InsertbefoRe (firstinstruction, writer. Create (OPCODES.LDC_I4, argumentcount-firstargument)); 20//Then instance of the object array, assigned to the array we created writ Er. InsertBefore (Firstinstruction, writer. Create (opcodes.newarr,22 assembly. Mainmodule.import (typeof (object)));//c# code description//object[] Arr=new Object[argumentcou Nt-firstargument] + for (int i = firstargument; i < ArgumentCount; i++)//Traverse parameter 27 {2 8 var parameter = method. parameters[i];29 30//Copy a value on the stack the writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.dup)); 32//Constant i-firstargument to stack, array [i-firstargument] this stuff. Writer. InsertBefore (Firstinstruction, writer. Create (OPCODES.LDC_I4, I-firstargument)), 34//press the i + thisshift parameter stack. Writer. InsertBefore (Firstinstruction, WRIter. Create (Opcodes.ldarg, (short) (i + Thisshift))), 36//boxed into Object37 toobject (assembly, Firstinstruction, parameter. ParameterType, writer), 38//stack to the array arr[i] assigns a value of the number of writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.stelem_ref));//c# code Description//arr[i]=value;43}4 4}45 Else46 {writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.ldnull));}49}50 public static void Toobject (Assemblydefinition assembly, in Struction firstinstruction, TypeReference Originaltype, ilprocessor writer) Wuyi {if (ORIGINALTYPE.ISV Aluetype) 53 {54//Normal value type for boxing operation, writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.box, Originaltype)),}57 else58 {if (origInaltype.isgenericparameter) 60 {61//collection boxed by writer. InsertBefore (Firstinstruction, writer. Create (Opcodes.box, assembly. Mainmodule.import (Originaltype)); 63}64 65}66}
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
Five: Business Preparation
I define a user class to inject, and then tag it.
1234567891011121314151617 |
[WeaveService]
public
static
class
UserManager
{
[Log]
public
static
string
GetUserName(
int
userId,
string
memberid)
{
return "成功"
;
}
[Log]
public
static
string
GetPoint(
int
x,
int
y)
{
var
sum = x + y;
return
"用户积分: "
+ sum;
}
}
|
Our usual business notation does not require any extra action.
123456789 |
public
static
void
Main(
string
[] args)
{
UserManager.GetUserName(1,
"v123465"
);
UserManager.GetPoint(2, 3);
Console.ReadLine();
}
|
Six: Inject call
I typed the business class into the D drive and injected it with our previous weave function.
Codeinject.weave (New string[] {@ "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
Dynamic acquisition of runtime data using mono Cecil (injected in atribute form)-From the network