C#可重用函数转储局部变量的当前值

我想编写一个可重用的函数,我可以在任何方法中调用它来记录所有局部变量的快照。 例如:

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 ,但我不知道如何使用reflection访问局部变量的值。

 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); } } 

reflectionAPI似乎非常适合静态分析,但不适合这样的动态分析。 例如,在第一次调用dumpLocalVariables期间,变量t不在范围内,但它仍然出现在MethodBodyLocalVariables属性中。

我怀疑有一个我忽略的调试API。 Developer Studio如何在断点处填充“本地人”选项卡? 有没有办法在运行时做类似的事情?

编辑:

我可以在ILSpy中看到我的示例类使用IL代码(如ldloc.0和ldloc.1)来获取第一个和第二个局部变量。

 .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 

也许我可以使用某种类似代理的机制让我做同样的事情? 我不介意调用我的可重用方法是否杂乱,我只是想要一些我可以粘贴到任何代码块而无需大量手工编辑的东西。

看到这个相关的问题:

有没有一种简单的方法来获取C#(或CIL)中当前堆栈帧中的所有局部变量

简短的回答是:您无法获取局部变量的值,因为它们在运行时直接在堆栈上分配,因此无法通过reflection获得。 实现这一目标的唯一方法是通过调试器API …而且它远非微不足道。 此外,这仅在您的自定义调试器实际附加到进程时才有效。

更好,更可行的选择可能是通过assembly编织。 您说您不希望方法必须知道在记录其值时要访问的局部变量的特定名称。 我建议创建两种方法:

 static void LogVariables(); 

 static void LogVariables(params string[] names, params object[] values); 

添加一个post build任务,该任务调用一个程序集编织例程,该例程将第一个LogVariables调用与第二个进行交换,但显式地为该方法提供变量名称/值。 您可以编写此例程来使用Mono Cecil修改程序集(还有其他工具可以执行此操作)。

http://www.mono-project.com/Cecil

通过使用外部调试器来管理代码是可能的。 有关如何完成操作,请参阅“托管调试器示例”: http : //blogs.msdn.com/b/jmstall/archive/2004/09/30/236281.aspx (包含示例链接和更多信息)

考虑使用自定义PostSharp方面(使用IL转换 ) 编写小型转储 。

一个共享的debuging引擎库,用C#编写。 可以在NuGet上以Microsoft.Samples.Debugging.MdbgEngine的forms获得。

PostSharp方面的代码在GitHub上可用,作为PADRE(可插入自动调试和报告引擎)存储库的一部分