C#可重用函数,用于转储局部变量的当前值
我想写一个可重用的函数,我可以在任何方法中调用它来记录所有局部变量的快照。例如:C#可重用函数,用于转储局部变量的当前值,c#,debugging,reflection,local-variables,code-reuse,C#,Debugging,Reflection,Local Variables,Code Reuse,我想写一个可重用的函数,我可以在任何方法中调用它来记录所有局部变量的快照。例如: void somemethod() { int a = 1; string s = "something"; dumpLocalVariables("step 1", MethodInfo.GetCurrentMethod(), this); a++; string t = s + "else"; du
void somemethod()
{
int a = 1;
string s = "something";
dumpLocalVariables("step 1", MethodInfo.GetCurrentMethod(), this);
a++;
string t = s + "else";
dumpLocalVariables("step 2", MethodInfo.GetCurrentMethod(), this);
}
我希望得到如下控制台输出:
step 1
Int32 a = 1
String s = something
step 2
Int32 a = 2
String s = something
String t = somethingelse
我希望避免提供局部变量名的特定列表
我能找到的最接近的方法是MethodInfo.GetCurrentMethod().GetMethodBody().LocalVariables
,但我不知道如何使用反射访问局部变量的值
void dumpLocalVariables(string context, MethodBase currentMethod, object obj)
{
Console.WriteLine(context);
MethodBody methodBody = currentMethod.GetMethodBody();
foreach (LocalVariableInfo lvi in methodBody.LocalVariables)
{
string variableType = lvi.LocalType.Name;
// how do I get this?
string variableName = "variableNameHere";
// how do I get this?
string variableValue = "variableValueHere";
Console.WriteLine(" " + variableType + " " + variableName +
" = " + variableValue);
}
}
反射API似乎非常适合静态分析,但不适合这样的动态分析。例如,变量t
在第一次调用dumpLocalVariables
期间不在范围内,但它仍然出现在MethodBody
的LocalVariables
属性中
我怀疑我忽略了一个调试API。当处于断点时,Developer Studio如何填充“locals”选项卡?有没有一种方法可以在运行时执行类似的操作 编辑: 我可以在ILSpy中看到,我的示例类使用像ldloc.0和ldloc.1这样的IL代码来获取第一个和第二个局部变量
.locals init (
[0] int32 a
[1] string s
[2] string t
)
后来
IL_001b: ldloc.0 // this is a
IL_001c: ldc.i4.1
IL_001d: add
IL_001e: stloc.0
IL_001f: ldloc.1 // this is s
IL_0020: ldstr "else"
IL_0025: call string string::Concat(string, string)
IL_002a: stloc.2 // this is t
也许我可以使用某种类似代理的机制,让我做同样的事情?我不介意对我的可重用方法的调用是否凌乱,我只想要一些我可以粘贴到任何代码块中而无需大量手工编辑的东西。请参阅此相关问题: 简单的回答是:您无法获取局部变量的值,因为它们在运行时直接在堆栈上分配,因此无法通过反射获得。要做到这一点,唯一的方法是通过调试器API…而且这绝非小事。此外,这仅在自定义调试器实际附加到进程时才起作用 更好、更可行的选择可能是通过装配编织。您说过您不想让方法在记录其值时必须知道要访问的局部变量的特定名称。我建议创建两种方法:
static void LogVariables();
及
添加一个生成后任务,该任务调用一个程序集编织例程,该例程将第一个LogVariables调用与第二个LogVariables调用交换,但显式地向方法提供变量名/值。您可以编写此例程来使用Mono-Cecil修改程序集(还有其他工具也可以这样做)
可以使用外部调试器处理托管代码。请参阅“托管调试器示例”了解其操作方法:(包括指向示例的链接和更多信息)考虑使用一个示例) 一个共享的调试引擎库,用C#编写。在NuGet上以Microsoft.Samples.Debugging.MdbgEngine的形式提供
PostSharp方面的代码可以在GitHub上找到,作为“我怀疑我忽略了一个调试API”:
System.Diagnostics.Debugger
@Henk:你能澄清一下吗?我不知道Debugger
类除了IsAttached
和Break()
之外还有什么有用的东西。可能的副本:,。可能的@Hank Holterman和@Groo:系统的副本。诊断。Debugger
在这种情况下没有提供任何帮助。谢谢你的链接。mdbg的内容很有趣。这将需要更多的前期工作,但我怀疑我可以在此基础上炮制一些东西来做我想做的事情。我并不认为只有我一个人意识到需要抛弃本地人,并且每次都必须一次性完成。博客链接到的mdbg v2.0下载不再可用。我找到了mdbg v4.0的下载。(谁知道它会在那里呆多久,现在已经快三年了。)这是迄今为止最简单的答案,但不是我想要的。我仍然想提出一些可以以“正常”的方式插入和编译的东西。我想没有更多的想法了,所以我很不情愿地接受了这个答案。我认为至少在运行时使用cecil程序集编写一些东西来执行这种日志记录是可行的,而不需要编译后调整。如果可以获得局部变量列表,为什么不可以通过反射生成动态代码。发射以转储它的值?
static void LogVariables(params string[] names, params object[] values);