假设我有一个方法
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
没有运行。
有没有办法从动作本身的外部获取动作的文件/行?
不确定此代码是否涵盖您的所有案例
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();
}
直接,没有
间接地,是的(有点)。但是您必须为获得答案的非常脆弱方式做好准备。
可以修改
PrintSourceCode
的签名来使用CallerMemberArgumentExpression:
private void PrintSourceCode(
Action action,
[CallerArgumentExpression(nameof(action))] string expression = null);
并且您可以修改
PrintSourceCode
的主体以删除您提到的“无关”信息(即() =>
部分,最后的)
部分和空格)。
没有办法从完全 声明 的角度得到你想要的东西,因为它不被任何当前版本的 C#/.NET 支持。你别无选择,只能求助于一些 命令式编程 给定你 can 以声明方式接收的信息。
命令式部分意味着使用算法(命令式)解析和处理声明性数据。 user2250152 的 answer 提供了一种方法来做到这一点,尽管必须修改它以从属性(编译时)而不是从运行时的堆栈帧数据中提取。
我想尝试将
Caller
属性应用于 Action
以外的委托,但这行不通。你失去了“动作”参数,所以没有什么可以挂在CallerMemberExpression
上。