在运行时调试C#方法

时间:2017-11-17 12:55:02

标签: c# reflection.emit codedom

我正在开发一个应该动态编译和调试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 

4 个答案:

答案 0 :(得分:0)

此配置可以帮助您:

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

答案 1 :(得分:0)

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

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

然后,您可以进入目标方法的Invokation。守则可能如下所示:

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

答案 2 :(得分:0)

Elchido在评论中指出,也许我应该寻找翻译。经过一番搜索,我遇到了CSI:一个简单的C#解释器。

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代码”转换为单独的行并提取变量。当我有更多/更好的代码时,我会发布更新。

答案 3 :(得分:-5)

  

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