如何返回C#方法调用的语法上下文

c#

如果你写这样的东西

this.MyMethod(this.MyMethod(myParam)).Should().BeNull();

使用FluentAssertions库,当断言失败时抛出异常,并显示消息

Expected this.MyMethod(this.MyMethod(myParam)) to be <null>, but found "foo".

它如何设法获取方法调用的语法上下文以生成如此有意义的异常消息?显然使用了某种反射,并且可能使用了一些堆栈跟踪检查(实际上,它仅在调试模式下和表达式写在一行中时才能正常工作),但究竟如何?

更具体地说,如何编写带有签名的方法

Expected this.MyMethod(this.MyMethod(myParam)) to be <null>, but found "foo".

满足(在调试模式下)以下内容?

public static string GetSyntacticContext(object parameter);

回答

您提到它仅在调试模式下工作,并且仅当表达式写在一行中时才有效。实际上,Debug 模式下的异常堆栈跟踪包含源文件的完整路径和导致异常发生位置的每个堆栈帧的行号。

因此,库可以从文件中读取该行并对其进行检查。它可能会对该行进行完整的表达式解析,但更有可能他们选择使用正则表达式的快速而肮脏的路线。在您引用的所有示例中,它真正需要做的就是删除.Should()及其后的所有内容。

在您的位置,我会稍微修改源文件(例如,改变间距和/或在行中间添加一些 /* 注释 */)以查看异常消息是否保留这些。如果是,我们就知道它是从源文件中读取的。如果没有,我敢打赌它仍然从源文件中读取,但会执行相关行的句法解析并重建它。

您假设的GetSyntacticContext方法可能会做类似的事情:获取当前堆栈帧及其文件名/行号信息,然后从文件中读取该行。像这样的东西:

public static string GetSyntacticContext(object parameter)
{
    var st = new StackTrace(fNeedFileInfo: true);
    var frame = st.GetFrame(1);
    return File.ReadLines(frame.GetFileName()).Skip(frame.GetFileLineNumber() - 1).FirstOrDefault();
}

请注意,此示例未使用任何parameter参数。在这个例子中,我没有尝试检测GetSyntacticContext对方法调用语法中的代码的调用和提取;它只返回整行代码、缩进等。

顺便说StackFrame一句,该类型也有一个GetMethod()方法,因此您可以获得对包含相关调用的方法的运行时引用GetSyntacticContext。不确定您可能会用它做什么,但您可以获得它的 IL 代码,和/或分析 EXE 文件附带的 PDB 文件的内容。不过,这不会真正为您提供实际的 C# 源代码;充其量 PDB 文件包含您已经拥有的相同文件名/行号信息,它仍然不允许您区分在GetSyntacticContext同一语句中发生的多个调用。


以上是如何返回C#方法调用的语法上下文的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>