从 MethodInfo 获取源文件/行

问题描述 投票:0回答:2

假设我有一个方法

PrintSourceCode(Action action)
接受 Action 委托并以这种方式执行:

PrintSourceCode(() => 
{ // need this line number
    DoSomething();
})

PrintSourceCode
我想打印通过的动作的源代码。

我能够得到

StackFrame
,然后读取源文件并输出它。然而,它会产生整个
PrintSourceCode()
调用的输出,而不仅仅是动作。

        static void PrintSourceCode(Action action)
        {
            action();
            
            var mi = action.GetMethodInfo(); // not currently used

            var frame = new StackFrame(1, true);
            var lineNumber = frame.GetFileLineNumber();
            var fileName = frame.GetFileName();
            var lines = File.ReadAllLines(fileName);
            var result = new StringBuilder();

            for (var currLineIndex = lineNumber - 1; currLineIndex < lines.Length; currLineIndex++)
            {
                var currentLine = lines[currLineIndex];
                result.AppendLine(currentLine);
                if (Regex.IsMatch(currentLine, @";\s*$"))
                {
                    break;
                }
            }

            Console.WriteLine(result.ToString());
        }

电流输出

PrintSourceCode(() =>
{
     DoSomething();

期望的输出

{
     DoSomething();
}

我可以调用

action.GetMethodInfo()
但是它似乎没有文件/行信息。并且没有办法获取/构建 StackFrame,因为
action
没有运行。

有没有办法从动作本身的外部获取动作的文件/行?

c# stack-trace stack-frame methodinfo
2个回答
0
投票

不确定此代码是否涵盖您的所有案例

static void PrintSourceCode(Action action)
{
    action();

    var frame = new StackFrame(1, true);
    var lineNumber = frame.GetFileLineNumber();
    var fileName = frame.GetFileName();
    var lines = File.ReadAllLines(fileName);
    var result = new StringBuilder();

    var bracket = 0;
    for (var currLineIndex = lineNumber; currLineIndex < lines.Length; currLineIndex++)
    {
        var currentLine = lines[currLineIndex];
          
        if (currentLine.Contains("{"))
        {
            bracket++;
        }
        else if (currentLine.Contains("}"))
        {
            bracket--;
        }
        if (bracket == 0)
        {
            currentLine = currentLine.Substring(0, currentLine.IndexOf("}") + 1);
            result.AppendLine(currentLine);
            break;
        }
        result.AppendLine(currentLine);
    }

    Console.WriteLine(result.ToString());
}

对于

PrintSourceCode(() => 
{
    DoSomething();
})

它产生

{
     DoSomething();
}

0
投票

直接,没有

间接地,是的(有点)。但是您必须为获得答案的非常脆弱方式做好准备。

可以修改

PrintSourceCode
的签名来使用CallerMemberArgumentExpression:

    private void PrintSourceCode(
        Action action,
        [CallerArgumentExpression(nameof(action))] string expression = null);

并且您可以修改

PrintSourceCode
的主体以删除您提到的“无关”信息(即
() =>
部分,最后的
)
部分和空格)。

没有办法从完全 声明 的角度得到你想要的东西,因为它不被任何当前版本的 C#/.NET 支持。你别无选择,只能求助于一些 命令式编程 给定你 can 以声明方式接收的信息。

命令式部分意味着使用算法(命令式)解析和处理声明性数据。 user2250152 的 answer 提供了一种方法来做到这一点,尽管必须修改它以从属性(编译时)而不是从运行时的堆栈帧数据中提取。

我想尝试将

Caller
属性应用于
Action
以外的委托,但这行不通。你失去了“动作”参数,所以没有什么可以挂在
CallerMemberExpression
上。

© www.soinside.com 2019 - 2024. All rights reserved.