C# 在生成.NET程序集的应用程序中调试该程序集
简而言之,问题是:如何调试在生成程序的调试会话期间生成的代码?(见下面的代码) 我面临以下问题:我想调试生成动态生成/编译代码的应用程序。我提供了一个过于简单的例子来说明这一点。这个例子不需要调试!我的真实应用程序生成了更多的行和代码,这些行和代码真正证明了调试的合理性,请相信我:-)我想知道是否有方法进行调试或在C# 在生成.NET程序集的应用程序中调试该程序集,c#,.net,debugging,code-generation,codedom,C#,.net,Debugging,Code Generation,Codedom,简而言之,问题是:如何调试在生成程序的调试会话期间生成的代码?(见下面的代码) 我面临以下问题:我想调试生成动态生成/编译代码的应用程序。我提供了一个过于简单的例子来说明这一点。这个例子不需要调试!我的真实应用程序生成了更多的行和代码,这些行和代码真正证明了调试的合理性,请相信我:-)我想知道是否有方法进行调试或在HelloWorld上设置断点。进入InvokeMethod调用不起作用。可能一个解决方案涉及在调用站点对生成的程序集进行代码修改 我已经看了很多问题(例如),但是没有一个对解决问题有
HelloWorld
上设置断点。进入InvokeMethod调用不起作用。可能一个解决方案涉及在调用站点对生成的程序集进行代码修改
我已经看了很多问题(例如),但是没有一个对解决问题有帮助(如果可以解决的话?)
我以源代码为基础,修复了过时的调用。除此之外,我在内存中动态生成了程序集,调用工作正常。我显式地生成了一个包含调试信息的程序集,这给了我希望:如果调试不可能,为什么会有这个选项
using System;
using System.Text;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace DynamicAssembly
{
class CreateCompileExecute
{
[STAThread]
static void Main(string[] args)
{
// Creates a text file to store the new class
StringBuilder builder = new StringBuilder();
builder.AppendLine("using System;");
builder.AppendLine("namespace CSharpFriendsRocks");
builder.AppendLine("{");
builder.AppendLine("class CSharpFriends");
builder.AppendLine("{");
builder.AppendLine("public CSharpFriends() {" +
" Console.WriteLine(\"The CSharpFriends type is constructed\"); }");
builder.AppendLine("public void HelloWorld() {" +
" Console.WriteLine(\"Hello World - CSharpFriends.Com Rocks.\"); }");
builder.AppendLine("}");
builder.AppendLine("}");
// Create the C# compiler
CSharpCodeProvider csCompiler = new CSharpCodeProvider();
// input params for the compiler
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.OutputAssembly = "CSharpFriends.dll";
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = true;
compilerParams.ReferencedAssemblies.Add("system.dll");
compilerParams.GenerateExecutable = false; // generate the DLL
// Run the compiler and build the assembly
CompilerResults results = csCompiler.CompileAssemblyFromSource(
compilerParams, builder.ToString());
// Load the generated assembly into the ApplicationDomain
Assembly asm = results.CompiledAssembly;
Type t = asm.GetType("CSharpFriendsRocks.CSharpFriends");
// BindingFlags enumeration specifies flags that control binding and
// the way in which the search for members and types is conducted by reflection.
// The following specifies the Access Control of the bound type
BindingFlags bflags = BindingFlags.DeclaredOnly | BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance;
// Construct an instance of the type and invoke the member method
Object obj = t.InvokeMember("HelloWorld", bflags |
BindingFlags.CreateInstance, null, null, null);
// Call the method
t.InvokeMember("HelloWorld", bflags | BindingFlags.InvokeMethod,
null, obj, null);
}
}
}
在发现我的问题是一个重复的问题后,我终于找到了一种解决方法,这对我来说并不明显。bbmud提供了一个很好的提示,让调试器正常工作,但没有告诉如何进入代码。我添加了对某个程序集的引用,该程序集包含我要在脚本中实现的接口:
compilerParams.ReferencedAssemblies.Add(typeof(IPlugin).Assembly.Location);
compilerParams.GenerateExecutable = false; // generate the DLL
// if you want to debug, this is needed...
compilerParams.GenerateInMemory = false;
compilerParams.TempFiles = new TempFileCollection(Environment.
GetEnvironmentVariable("TEMP"), true);
<>现在,当我考虑<代码> cSARPultBuffs/Cuth>是<代码> IPlugin < /代码>的实现时,我可以通过上面的<代码> Obj> <代码>获得接口:
IPlugin script = obj as IPlugin;
然后调试对接口方法或属性的调用就像往常一样简单!添加的技巧
System.Diagnostics.Debugger.Break();
在脚本内部,代码也可以正常工作,但需要对脚本进行更改。由于应用程序中的代码总是需要根据某种机制(使用属性或接口的反射)知道脚本中有什么类型的方法,因此使用双方都知道的接口对我来说是一个非常可接受的解决方案
我希望它能帮助其他人。Visual Studio 2010在调试器中温和地处理此问题。升级后我很惊讶。我希望它能有所帮助。你看到了吗?我想真正地调试它,而不是可视化IL代码,或者我遗漏了什么?或者你的意思是其中的答案说这是不可能的吗?我正在谈论的是,它向你展示了如何使用windbg调试代码。我明白了。我对调试的期望更高一些!我知道windbg只是为了驱动程序开发。如果这是唯一的方法,我甚至更愿意使用一些停止/逐步事件机制来插入生成的代码,而不是使用那些东西。但是谢谢你的提示:-)。希望有人有想法使用VS.NET IDE调试器…我正在努力处理程序终止后磁盘上剩余的临时文件。将TempFileCollection的第二个参数设置为false不是一个选项,因为这样调试就不再工作了。。。我对文件进行单手处理(IDisposable实现),并且必须相应地处理AppDomains