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。