【问题标题】:Debug C# method at runtime在运行时调试 C# 方法
【发布时间】:2018-05-01 06:15:03
【问题描述】:

我正在开发一个可以即时编译和调试 C# 代码的应用程序。

下面包含代码的简化版本。

这段代码应该做些什么来逐步运行生成的方法并在每一步之后获取变量x和y的状态?

如果一切都应该改变就好了,我很高兴有任何建设性的回应。

编辑:澄清一下:我想做的是让我的代码调试使用反射生成的代码,而不是 Visual Studio 中的调试功能。

string code = 
@"
namespace MyNameSpace
{
    public class MyClass
    {
        public static int MyMethod()
        {
            var x = 3;
            var y = 4;
            return x * y;
        }
    }
}";

string namespaceName = "MyNameSpace";
string className = "MyClass";
string methodName = "MyMethod";
string language = "csharp";
string classFullname = namespaceName + "." + className;

CodeDomProvider provider = CodeDomProvider.CreateProvider(language);
CompilerParameters parameters = new CompilerParameters();
CompilerResults results;

parameters.OutputAssembly = "Compiler";

parameters.CompilerOptions = "/t:library";
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
parameters.IncludeDebugInformation = true;

results = provider.CompileAssemblyFromSource(parameters, code);

if (results.Errors.Count != 0)
{
    throw new Exception("Code compilation errors occurred.");
}

var instance = results.CompiledAssembly.CreateInstance(classFullname, false);

// TODO run the method step by step and get the state after each step 

【问题讨论】:

  • “和调试 C# 代码” - 我会说这非常困难和广泛。
  • 在你生成的代码中加入一个Debugger.Break(); call,看看它是否被命中,你可以从那里更进一步吗?
  • 好像是this question的副本。
  • 我认为这是不可能的。调试器是一个独立的进程,它通过操作系统服务与被调试者通信。调试对象必须使用指向原始源的调试信息进行编译,并生成适当的 pdb 伴侣。也许您正在寻求解释 C# 代码?
  • @MartiendeJong 这个页面 [codeguru.com/cpp/v-s/debug/debuggers/article.php/c16451/… 可以让您了解编写调试器所涉及的内容。

标签: c# reflection.emit codedom


【解决方案1】:

此配置可能对您有所帮助:

parameters.GenerateInMemory = false; //default
parameters.TempFiles = new 
TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
parameters.IncludeDebugInformation = true;
parameters.TempFiles.KeepFiles = true

【讨论】:

  • 与 OP 的问题有什么不同,为什么可能会有所帮助?
  • 如果你有 pdb 文件可以调试,通过上面的设置你告诉代码生成器保留 pdb 文件并且不要优化生成的文件
  • 这个答案有确切的duplicate
  • 我的代码的不同之处在于,它包含了一个保存临时(PDB?)文件的指令。我假设因为我编译到内存中,所以 PDB 也保存在内存中。你知道是不是这样吗?感谢您的回答。
  • @Sinatr 这不是您提到的问题的重复,因为我想在运行时检索调试信息,而不是在 Visual Studio 中调试。
【解决方案2】:

要调试生成的代码,您需要 pdb 文件。要在调试应用程序时使用它们,只需告诉编译器将临时文件保存在哪里。为此,您只需将以下行添加到您的参数中:

parameters.TempFiles = new TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);

然后您可以进入目标方法的调用。代码可能如下所示:

var method = instance?.GetType().GetMethod(methodName);
method?.Invoke(instance, BindingFlags.InvokeMethod, null, null, CultureInfo.CurrentCulture);

如果您希望调试器自动停止,在输入“MyMethod”时,您可以像这样修改您的字符串:

string code =
@"using System.Diagnostics;

namespace MyNameSpace
{
    public class MyClass
    {
        public int MyMethod()
        {
            Debugger.Break();
            var x = 3;
            var y = 4;
            return x * y;
        }
    }
}";

【讨论】:

    【解决方案3】:

    Elchido 在 cmets 中指出,也许我应该寻找翻译。经过一番搜索,我遇到了 CSI: A Simple C# Interpreter。

    https://www.codeproject.com/Articles/10212/CSI-A-Simple-C-Interpreter

    经过调查,我的结论是可以使用和解释器或 Codedom 编译器来创建类似调试器的功能,但需要付出很大的努力。

    我正在研究的解决方案是将代码拆分为单独的语句并将所有变量放在一个数组中。

    'MyMethod' 函数被分成几部分:

    public static object Line1()
    {
        return 3;
    }
    
    public static object Line2()
    {
        return 4;
    }
    
    public static object Line3(object x, object y)
    {
        return x*y;
    }
    

    使用 Codedom 编译器编译代码后,我可以执行以下操作:

    Dictionary<string, object> vars = new Dictionary<string, object>();
    
    List<MethodInfo> lines = new List<MethodInfo>();
    lines.Add(type.GetMethod("Line1"));
    lines.Add(type.GetMethod("Line2"));
    lines.Add(type.GetMethod("Line3"));
    
    vars["x"] = lines[0].Invoke(instance, new object[] { });
    vars["y"] = lines[1].Invoke(instance, new object[] { });
    vars["@return"] = lines[2].Invoke(instance, new object[] { vars["x"], vars["y"] });
    

    请注意,这还不是一个可行的解决方案,仍然需要做很多工作才能将“MyMethod 代码”转换为单独的行并提取变量。当我有更多/更好的代码时,我会发布更新。

    【讨论】:

      【解决方案4】:

      点击代码左侧会标记红点,称为断点。之后,当您的代码执行到该点时,它将在该点中断,您可以按 F10 键逐步调试。

      【讨论】:

      • 您将在字符串上放置一个断点。这有什么帮助?
      • 告诉我你到底想做什么?
      • OP 想要调试作为源代码提供的代码:string 变量code 中的文本。普通的VS断点不能放在这样的代码里面。
      猜你喜欢
      • 2011-12-20
      • 2021-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多