让PostSharp帮助记录IF语句

时间:2015-10-02 21:52:58

标签: c# aop postsharp

我正在寻找的行为如下:

[IfElseLogging]
public void Foo(string bar)
{
    if (bar == "somedumbstringbecausethisishorriblewayofdoingthings")
    {
        // here the aspect would log that the if statement above was true,
        // and thus took this path
    }
    else
    {
        // here the aspect would log that the if statement above was false,
        // and thus took this path
    }
}

如果有办法劫持if功能,我可以使用Postsharp使用的日志记录来装饰它并从我的手上除去灰尘。我加入问题的另一个原因是我不确定我是否清楚我要问的是什么。

这是一个由Jr开发人员完成的项目。我的任务不仅仅是重构,而是记录代码对流程图级别的确切作用。鉴于代码的性质,缺乏描述,糟糕的技术和实践,项目的性质等等......以下是我正在努力解决的问题:

  • 我不能简单地在本地调试和逐步执行代码
  • 我无法安全地创建单元测试和重构
  • 我无法理解这段代码的作用!
  • 我没有原始要求文件来了解该功能的目标是什么

所以我希望使用Postsharp来基本上给我我的代码路径和单元测试标准,因为我不知道如何获得它。

另一个想法是,是否有可能在找到if语句时触发事件的方面?

2 个答案:

答案 0 :(得分:2)

使用PostSharp进行面向方面编程将允许您创建拦截器,这些拦截器会在方法调用和属性访问等明确定义的点处挂钩您的代码。这样做就是重写从源代码生成的IL。

在您的情况下,您正在寻找特定的 <Charting:Chart.Series> <Charting:PieSeries x:Name="MySeries" Title="Population" IndependentValueBinding="{Binding Name}" DependentValueBinding="{Binding Amount}" IsSelectionEnabled="False" Width="125" Height="125" /> </Charting:Chart.Series> <ControlTemplate TargetType="series:LegendItem"> <StackPanel Orientation="Horizontal"> <datavis:Title Content="{TemplateBinding Content}" /> <TextBlock Text="{Binding DependentValueBinding, ElementName=MySeries}" /> </StackPanel> </ControlTemplate> 语句,但在生成的IL中不容易识别它们。以下是为您的示例方法生成的内容:

          nop
          ldarg.1     
          ldstr       "somedumbstringbecausethisishorriblewayofdoingthings"
          call        System.String.op_Equality
          stloc.0
          ldloc.0
          brfalse.s   NotEqual
          nop

**True branch**

          br.s        Return
NotEqual: nop

**False branch**

Return:   ret

但是,这是非优化版本。优化编译器生成此代码:

          ldarg.1
          ldstr       "somedumbstringbecausethisishorriblewayofdoingthings"
          call        System.String.op_Equality
          brfalse.s   NotEqual

**True branch**

          ret

NotEqual:

**False branch**

           ret

因此,如果你想进行IL重写,可以想象拦截方法调用,寻找类似于if的IL签名,然后重写IL来修改代码。但是,这种方法非常脆弱。源代码中的细微差别可能会生成具有不同签名的IL,并且只有编译器编写者才能真正了解您所查找的整个IL签名范围。如果条件语句涉及与逻辑运算符结合的多个术语,那么确定插入检测代码的位置会变得非常复杂。然后有误报。就个人而言,我认为这不是一个可行的策略来检测你的代码。

但是,您有另一种选择。您可以使用Roslyn编译源代码并使用Roslyn重写器来修改原始源代码树。这是源级别的AOP,而不是在IL级别提供AOP的PostSharp。

要重写语法树,您需要从ldstr, "...", call System.String.op_Equality, brfalse.s派生一个类。此重写器将修改CSharpSyntaxRewriter语句,以便覆盖if方法:

VisitIfStatement

要插入检测代码class IfStatementRewriter : CSharpSyntaxRewriter { public override SyntaxNode VisitIfStatement(IfStatementSyntax ifStatement) { var containsMagicString = ifStatement .Condition .DescendantNodes() .Any( syntaxNode => syntaxNode.ToString() == @"""somedumbstringbecausethisishorriblewayofdoingthings""" ); if (!containsMagicString) // Do not modify if statement. return ifStatement; // Only look at the "true" part and assume it is a block (has curly braces). var block = ifStatement.Statement as BlockSyntax; if (block == null) // Do not modify if statement. return ifStatement; // Insert instrumentation code at start of block. var instrumentationStatements = CreateInstrumentationStatements("True branch"); var modifiedStatements = block.Statements.InsertRange(0, instrumentationStatements); var modifiedBlock = block.WithStatements(modifiedStatements); return ifStatement.WithStatement(modifiedBlock); } } ,使用以下相当有毛的方法:

System.Console.WriteLine("True branch");

您现在可以修改语法树:

IEnumerable<StatementSyntax> CreateInstrumentationStatements(String text) {
  return SyntaxFactory.SingletonList<StatementSyntax>(
    SyntaxFactory.ExpressionStatement(
      SyntaxFactory.InvocationExpression(
        SyntaxFactory.MemberAccessExpression(
          SyntaxKind.SimpleMemberAccessExpression,
          SyntaxFactory.MemberAccessExpression(
            SyntaxKind.SimpleMemberAccessExpression,
            SyntaxFactory.IdentifierName("System"),
            SyntaxFactory.IdentifierName("Console")
          )
          .WithOperatorToken(SyntaxFactory.Token(SyntaxKind.DotToken)),
          SyntaxFactory.IdentifierName("WriteLine")
        )
        .WithOperatorToken(SyntaxFactory.Token(SyntaxKind.DotToken))
      )
      .WithArgumentList(
        SyntaxFactory.ArgumentList(
          SyntaxFactory.SeparatedList(
            new[] {
              SyntaxFactory.Argument(
                SyntaxFactory.LiteralExpression(
                  SyntaxKind.StringLiteralExpression,
                  SyntaxFactory.Literal(text)
                )
              )
            }
          )
        )
      )
    )
    .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
  );
}

您需要大大扩展代码以更好地过滤var root = (CompilationUnitSyntax) syntaxTree.GetRoot(); var rewriter = new IfStatementRewriter(); var rewrittenRoot = rewriter.Visit(root); 语句并处理if语句的所有不同方式,但与进行IL重写相比,这应该会让您更高成功的机会。

答案 1 :(得分:0)

您应该继承import pandas as pd aframe = pd.read_csv('thefile.csv') Out[19]: Name Value Value2 Value3 Rating 0 ddf 34 45 46 ok 1 ddf 67 23 11 ok 2 ghd 23 11 78 bad 3 ghd 56 33 78 bad r = aframe.groupby(['Name','Rating'],as_index=False).sum() Out[40]: Name Rating Value Value2 Value3 0 ddf ok 101 68 57 1 ghd bad 79 44 156 并覆盖OnMethodBoundaryAspectOnEntry(MethodExecutionArgs args)并覆盖OnExceptionAspect。您可以从args

获取并比较OnException(MethodExecutionArgs args)