postsharp 对我的方法的 cil 进行了哪些修改,阻止我编辑 cil 代码?
What modifications postsharp bring to the cilof my method that prevent me from editing the cil code?
我有这个方法:
public string NestedFoo(SampleClass bar)
{
var1 = "value set in NestedFoo()";
Var2 = "value set in NestedFoo()";
var3 = "value set in NestedFoo()";
Var4 = "value set in NestedFoo()";
AddPerson("From", "NestedFoo", 2);
return Foo();
}
cil 看起来像这样(从 ildasm 中获取并且与我的 c# cil 解析器告诉我的准确):
.method public hidebysig newslot virtual final
instance string NestedFoo(class WcfExceptionHandlingPocLib.SampleClass bar) cil managed
{
// Code size 75 (0x4b)
.maxstack 4
.locals init ([0] string V_0)
IL_0000: nop
IL_0001: ldstr "value set in NestedFoo()"
IL_0006: stsfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var1
IL_000b: ldstr "value set in NestedFoo()"
IL_0010: call void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var2(string)
IL_0015: nop
IL_0016: ldarg.0
IL_0017: ldstr "value set in NestedFoo()"
IL_001c: stfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var3
IL_0021: ldarg.0
IL_0022: ldstr "value set in NestedFoo()"
IL_0027: call instance void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var4(string)
IL_002c: nop
IL_002d: ldarg.0
IL_002e: ldstr "From"
IL_0033: ldstr "NestedFoo"
IL_0038: ldc.i4.2
IL_0039: conv.i8
IL_003a: call instance int32 WcfExceptionHandlingPocLib.ExceptionHandlingService::AddPerson(string,
string,
int64)
IL_003f: pop
IL_0040: ldarg.0
IL_0041: call instance string WcfExceptionHandlingPocLib.ExceptionHandlingService::Foo()
IL_0046: stloc.0
IL_0047: br.s IL_0049
IL_0049: ldloc.0
IL_004a: ret
} // end of method ExceptionHandlingService::NestedFoo
然后我继续将从方法体获得的 IL 代码解析为 IL 指令列表:
MethodInfo NestedFooInfo = [...];
byte[] nestedFooIl = NestedFooInfo.GetMethodBody().GetILAsByteArray();
List<ILInstruction> methodILInstructions = IlParser.parseIL(nestedFooIl);
ILInstruction class 看起来像这样:
public class ILInstruction
{
public OpCode Code { get; set; }
public byte[] OperandData { get; set; }
}
一旦有了这个列表,我就会在方法的开头添加一个 nop
指令:
var nopInstruction= new ILInstruction()
{
Code = OpCodes.Nop,
OperandData = null
};
methodILInstructions.Insert(0, nopInstruction);
并将其转换回字节数组:
var newIlCode = IlParser.getIlCode(methodILInstructions);
然后更新方法体代码:
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCode);
效果很好。而且我几乎可以在代码的任何地方添加指令(不仅是 nop
)。
但是,当我向此方法添加一个 postsharp 方面时,它会生成很多额外的 CIL 代码。
NestedFoo
IL 代码现在如下所示:
.method public hidebysig newslot virtual final
instance string NestedFoo(class WcfExceptionHandlingPocLib.SampleClass bar) cil managed
{
// Code size 213 (0xd5)
.maxstack 4
.locals init ([0] string V_0,
[1] string CS__returnValue,
[2] class [PostSharp]PostSharp.Aspects.MethodExecutionArgs CS[=17=]__aspectArgs,
[3] class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass> CS[=17=]__CS[=17=]__args,
[4] class [mscorlib]System.Reflection.MethodBase CS[=17=],
[5] class [mscorlib]System.Exception CS[=17=]__exception)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: newobj instance void class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass>::.ctor()
IL_0007: stloc.3
IL_0008: ldloc.3
IL_0009: ldarg.1
IL_000a: stfld !0 class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass>::Arg0
IL_000f: ldloc.3
IL_0010: newobj instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::.ctor(object,
class [PostSharp]PostSharp.Aspects.Arguments)
IL_0015: stloc.2
IL_0016: ldloc.2
IL_0017: ldsfld class [mscorlib]System.Reflection.MethodBase PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::_e
IL_001c: stloc.s CS[=17=]
IL_001e: ldloc.s CS[=17=]
IL_0020: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Method(class [mscorlib]System.Reflection.MethodBase)
IL_0025: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_002a: ldloc.2
IL_002b: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnEntry(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
.try
{
IL_0030: nop
IL_0031: ldstr "value set in NestedFoo()"
IL_0036: stsfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var1
IL_003b: ldstr "value set in NestedFoo()"
IL_0040: call void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var2(string)
IL_0045: nop
IL_0046: ldarg.0
IL_0047: ldstr "value set in NestedFoo()"
IL_004c: stfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var3
IL_0051: ldarg.0
IL_0052: ldstr "value set in NestedFoo()"
IL_0057: call instance void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var4(string)
IL_005c: nop
IL_005d: ldarg.0
IL_005e: ldstr "From"
IL_0063: ldstr "NestedFoo"
IL_0068: ldc.i4.2
IL_0069: conv.i8
IL_006a: call instance int32 WcfExceptionHandlingPocLib.ExceptionHandlingService::AddPerson(string,
string,
int64)
IL_006f: pop
IL_0070: ldarg.0
IL_0071: call instance string WcfExceptionHandlingPocLib.ExceptionHandlingService::Foo()
IL_0076: stloc.0
IL_0077: br.s IL_0079
IL_0079: ldloc.0
IL_007a: stloc.1
IL_007b: leave.s IL_007d
IL_007d: nop
IL_007e: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_0083: ldloc.2
IL_0084: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnSuccess(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
IL_0089: leave.s IL_00d3
} // end .try
catch [mscorlib]System.Exception
{
IL_008b: stloc.s CS[=17=]__exception
IL_008d: ldloc.2
IL_008e: ldloc.s CS[=17=]__exception
IL_0090: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Exception(class [mscorlib]System.Exception)
IL_0095: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_009a: ldloc.2
IL_009b: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnException(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
IL_00a0: ldloc.2
IL_00a1: call instance valuetype [PostSharp]PostSharp.Aspects.FlowBehavior [PostSharp]PostSharp.Aspects.MethodExecutionArgs::get_FlowBehavior()
IL_00a6: switch (
IL_00bf,
IL_00c1,
IL_00bf,
IL_00c1,
IL_00ca)
IL_00bf: rethrow
IL_00c1: ldloc.2
IL_00c2: ldnull
IL_00c3: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Exception(class [mscorlib]System.Exception)
IL_00c8: leave.s IL_00d3
IL_00ca: ldloc.2
IL_00cb: call instance class [mscorlib]System.Exception [PostSharp]PostSharp.Aspects.MethodExecutionArgs::get_Exception()
IL_00d0: throw
IL_00d1: leave.s IL_00d3
} // end handler
IL_00d3: ldloc.1
IL_00d4: ret
} // end of method ExceptionHandlingService::NestedFoo
每当我添加一条指令(例如 nop
)时,我都会得到:
System.InvalidProgramException: 'Common Language Runtime detected an invalid program.'
我完全不知道为什么。
我很确定解析 deparsing 效果很好,即使使用 postsharp 代码也是如此,因为如果我不添加 nop
指令。我从方法体中获取的字节数组和我从 var newIlCode = IlParser.getIlCode(methodILInstructions);
中获取的字节数组完全相同(使用 IEnumerable.SequenceEqual(...)
.
进行测试
我只用 nop
添加了 1 个字节,它就开始崩溃了。
知道为什么吗?
编辑:
我为什么要这样做? => 我需要记录对对象所做的所有修改。请参阅此 以了解我为何遵循此路径的解释。
为什么我的意思是“当我向此方法添加一个 postsharp 方面时”=> 我将一个属性应用于要应用的方法 this aspect。方面是将在方法执行之前和之后执行(在这种情况下)的代码部分,并且 if 出现异常。在我的例子中,方面实现真的很长而且并不真正相关。
PostSharp 将异常处理块添加到您的代码中。您需要在方法头中的异常处理子句中正确更改 offsets/lengths 以反映添加的指令。由于您添加了一条指令,这些间隔可能指向指令的中间并且 JIT 无法处理该方法。
如果您在原始代码中有异常处理,也会发生这种情况。
有关详细信息,请参阅 ECMA-335 的第 II 部分 25.4。
我有这个方法:
public string NestedFoo(SampleClass bar)
{
var1 = "value set in NestedFoo()";
Var2 = "value set in NestedFoo()";
var3 = "value set in NestedFoo()";
Var4 = "value set in NestedFoo()";
AddPerson("From", "NestedFoo", 2);
return Foo();
}
cil 看起来像这样(从 ildasm 中获取并且与我的 c# cil 解析器告诉我的准确):
.method public hidebysig newslot virtual final
instance string NestedFoo(class WcfExceptionHandlingPocLib.SampleClass bar) cil managed
{
// Code size 75 (0x4b)
.maxstack 4
.locals init ([0] string V_0)
IL_0000: nop
IL_0001: ldstr "value set in NestedFoo()"
IL_0006: stsfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var1
IL_000b: ldstr "value set in NestedFoo()"
IL_0010: call void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var2(string)
IL_0015: nop
IL_0016: ldarg.0
IL_0017: ldstr "value set in NestedFoo()"
IL_001c: stfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var3
IL_0021: ldarg.0
IL_0022: ldstr "value set in NestedFoo()"
IL_0027: call instance void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var4(string)
IL_002c: nop
IL_002d: ldarg.0
IL_002e: ldstr "From"
IL_0033: ldstr "NestedFoo"
IL_0038: ldc.i4.2
IL_0039: conv.i8
IL_003a: call instance int32 WcfExceptionHandlingPocLib.ExceptionHandlingService::AddPerson(string,
string,
int64)
IL_003f: pop
IL_0040: ldarg.0
IL_0041: call instance string WcfExceptionHandlingPocLib.ExceptionHandlingService::Foo()
IL_0046: stloc.0
IL_0047: br.s IL_0049
IL_0049: ldloc.0
IL_004a: ret
} // end of method ExceptionHandlingService::NestedFoo
然后我继续将从方法体获得的 IL 代码解析为 IL 指令列表:
MethodInfo NestedFooInfo = [...];
byte[] nestedFooIl = NestedFooInfo.GetMethodBody().GetILAsByteArray();
List<ILInstruction> methodILInstructions = IlParser.parseIL(nestedFooIl);
ILInstruction class 看起来像这样:
public class ILInstruction
{
public OpCode Code { get; set; }
public byte[] OperandData { get; set; }
}
一旦有了这个列表,我就会在方法的开头添加一个 nop
指令:
var nopInstruction= new ILInstruction()
{
Code = OpCodes.Nop,
OperandData = null
};
methodILInstructions.Insert(0, nopInstruction);
并将其转换回字节数组:
var newIlCode = IlParser.getIlCode(methodILInstructions);
然后更新方法体代码:
InjectionHelper.UpdateILCodes(NestedFooInfo, newIlCode);
效果很好。而且我几乎可以在代码的任何地方添加指令(不仅是 nop
)。
但是,当我向此方法添加一个 postsharp 方面时,它会生成很多额外的 CIL 代码。
NestedFoo
IL 代码现在如下所示:
.method public hidebysig newslot virtual final
instance string NestedFoo(class WcfExceptionHandlingPocLib.SampleClass bar) cil managed
{
// Code size 213 (0xd5)
.maxstack 4
.locals init ([0] string V_0,
[1] string CS__returnValue,
[2] class [PostSharp]PostSharp.Aspects.MethodExecutionArgs CS[=17=]__aspectArgs,
[3] class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass> CS[=17=]__CS[=17=]__args,
[4] class [mscorlib]System.Reflection.MethodBase CS[=17=],
[5] class [mscorlib]System.Exception CS[=17=]__exception)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: newobj instance void class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass>::.ctor()
IL_0007: stloc.3
IL_0008: ldloc.3
IL_0009: ldarg.1
IL_000a: stfld !0 class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass>::Arg0
IL_000f: ldloc.3
IL_0010: newobj instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::.ctor(object,
class [PostSharp]PostSharp.Aspects.Arguments)
IL_0015: stloc.2
IL_0016: ldloc.2
IL_0017: ldsfld class [mscorlib]System.Reflection.MethodBase PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::_e
IL_001c: stloc.s CS[=17=]
IL_001e: ldloc.s CS[=17=]
IL_0020: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Method(class [mscorlib]System.Reflection.MethodBase)
IL_0025: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_002a: ldloc.2
IL_002b: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnEntry(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
.try
{
IL_0030: nop
IL_0031: ldstr "value set in NestedFoo()"
IL_0036: stsfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var1
IL_003b: ldstr "value set in NestedFoo()"
IL_0040: call void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var2(string)
IL_0045: nop
IL_0046: ldarg.0
IL_0047: ldstr "value set in NestedFoo()"
IL_004c: stfld string WcfExceptionHandlingPocLib.ExceptionHandlingService::var3
IL_0051: ldarg.0
IL_0052: ldstr "value set in NestedFoo()"
IL_0057: call instance void WcfExceptionHandlingPocLib.ExceptionHandlingService::set_Var4(string)
IL_005c: nop
IL_005d: ldarg.0
IL_005e: ldstr "From"
IL_0063: ldstr "NestedFoo"
IL_0068: ldc.i4.2
IL_0069: conv.i8
IL_006a: call instance int32 WcfExceptionHandlingPocLib.ExceptionHandlingService::AddPerson(string,
string,
int64)
IL_006f: pop
IL_0070: ldarg.0
IL_0071: call instance string WcfExceptionHandlingPocLib.ExceptionHandlingService::Foo()
IL_0076: stloc.0
IL_0077: br.s IL_0079
IL_0079: ldloc.0
IL_007a: stloc.1
IL_007b: leave.s IL_007d
IL_007d: nop
IL_007e: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_0083: ldloc.2
IL_0084: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnSuccess(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
IL_0089: leave.s IL_00d3
} // end .try
catch [mscorlib]System.Exception
{
IL_008b: stloc.s CS[=17=]__exception
IL_008d: ldloc.2
IL_008e: ldloc.s CS[=17=]__exception
IL_0090: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Exception(class [mscorlib]System.Exception)
IL_0095: ldsfld class [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect PostSharp.ImplementationDetails._6104080c.'<>z__a_1'::a4
IL_009a: ldloc.2
IL_009b: callvirt instance void [WcfExceptionHandlingPocErrorProcessing]WcfExceptionHandlingPocErrorProcessing.Aspects.MethodBoundaryAspect::OnException(class [PostSharp]PostSharp.Aspects.MethodExecutionArgs)
IL_00a0: ldloc.2
IL_00a1: call instance valuetype [PostSharp]PostSharp.Aspects.FlowBehavior [PostSharp]PostSharp.Aspects.MethodExecutionArgs::get_FlowBehavior()
IL_00a6: switch (
IL_00bf,
IL_00c1,
IL_00bf,
IL_00c1,
IL_00ca)
IL_00bf: rethrow
IL_00c1: ldloc.2
IL_00c2: ldnull
IL_00c3: call instance void [PostSharp]PostSharp.Aspects.MethodExecutionArgs::set_Exception(class [mscorlib]System.Exception)
IL_00c8: leave.s IL_00d3
IL_00ca: ldloc.2
IL_00cb: call instance class [mscorlib]System.Exception [PostSharp]PostSharp.Aspects.MethodExecutionArgs::get_Exception()
IL_00d0: throw
IL_00d1: leave.s IL_00d3
} // end handler
IL_00d3: ldloc.1
IL_00d4: ret
} // end of method ExceptionHandlingService::NestedFoo
每当我添加一条指令(例如 nop
)时,我都会得到:
System.InvalidProgramException: 'Common Language Runtime detected an invalid program.'
我完全不知道为什么。
我很确定解析 deparsing 效果很好,即使使用 postsharp 代码也是如此,因为如果我不添加 nop
指令。我从方法体中获取的字节数组和我从 var newIlCode = IlParser.getIlCode(methodILInstructions);
中获取的字节数组完全相同(使用 IEnumerable.SequenceEqual(...)
.
我只用 nop
添加了 1 个字节,它就开始崩溃了。
知道为什么吗?
编辑:
我为什么要这样做? => 我需要记录对对象所做的所有修改。请参阅此
为什么我的意思是“当我向此方法添加一个 postsharp 方面时”=> 我将一个属性应用于要应用的方法 this aspect。方面是将在方法执行之前和之后执行(在这种情况下)的代码部分,并且 if 出现异常。在我的例子中,方面实现真的很长而且并不真正相关。
PostSharp 将异常处理块添加到您的代码中。您需要在方法头中的异常处理子句中正确更改 offsets/lengths 以反映添加的指令。由于您添加了一条指令,这些间隔可能指向指令的中间并且 JIT 无法处理该方法。
如果您在原始代码中有异常处理,也会发生这种情况。
有关详细信息,请参阅 ECMA-335 的第 II 部分 25.4。