首页 > 解决方案 > postsharp 对我的方法的 cilof 进行了哪些修改,阻止我编辑 cil 代码?

问题描述

我有这个方法:

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 类看起来像这样:

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 代码。IL 代码现在NestedFoo如下所示:

.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$1$1__returnValue,
             [2] class [PostSharp]PostSharp.Aspects.MethodExecutionArgs CS$0$2__aspectArgs,
             [3] class [PostSharp]PostSharp.Aspects.Internals.Arguments`1<class WcfExceptionHandlingPocLib.SampleClass> CS$0$3__CS$0$3__args,
             [4] class [mscorlib]System.Reflection.MethodBase CS$0$4,
             [5] class [mscorlib]System.Exception CS$0$5__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$0$4
    IL_001e:  ldloc.s    CS$0$4
    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$0$5__exception
      IL_008d:  ldloc.2
      IL_008e:  ldloc.s    CS$0$5__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:“公共语言运行时检测到无效程序。”

我完全不知道为什么。我很确定解析 deparsing 运行良好,即使使用 postsharp 代码,因为如果我不添加nop指令。我从方法体得到的字节数组和我得到的字节数组var newIlCode = IlParser.getIlCode(methodILInstructions);完全一样(用IEnumerable.SequenceEqual(...).

我只是添加了 1 个字节,nop它开始崩溃。知道为什么吗?

编辑:

我为什么要这样做?=> 我需要记录对对象所做的所有修改。请参阅此如何在给定时间保留对对象状态的引用?解释我为什么要走这条路。

为什么我的意思是“当我向这个方法添加一个后锐化方面时”=>我将一个属性应用于该方法以应用这个方面一个方面是在方法执行之前和之后以及如果出现异常时将执行的代码部分(在这种情况下) 。在我的情况下,方面的实现真的很长而且不是很相关。

标签: c#clrjitcilpostsharp

解决方案


PostSharp 将异常处理块添加到您的代码中。您需要在方法头中的异常处理子句中正确更改偏移量/长度以反映添加的指令。由于您添加了一条指令,因此这些间隔可能指向指令的中间,并且 JIT 无法处理该方法。

如果您在原始代码中进行异常处理,也会发生这种情况。

有关详细信息,请参阅ECMA-335的第 II 部分 25.4 。


推荐阅读