2009-10-20 81 views
11

问题简而言之:如何调试在生成程序的调试会话期间生成的代码? (见下面的代码)从生成它的应用程序中调试生成的.NET程序集

我面临以下问题:我想从生成它的应用程序调试到动态生成/编译的代码。我提供了一个简单的例子来澄清它。这个例子不需要调试!我真正的应用程序生成了更多的线路和代码,真正证明调试是正确的,相信我:-)我想知道是否有方法来调试或在HelloWorld处设置断点。进入InvokeMethod调用不起作用。也许解决方案涉及在调用站点对生成的程序集进行代码修改。

我看了一下已经有很多问题(Debug dynamically loaded assembly in Visual Studio .NET例如),但没有一个解决问题有帮助(如果可解呢?)

我把代码http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=118为基础,固定的已经过时的电话。除此之外,我在内存中动态生成程序集,并且调用运行良好。我显式生成了一个包含调试信息的程序集,它给了我希望:如果调试不可行,为什么会有这个选项?

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

你见过http://stackoverflow.com/questions/321203/how-do-i-debug-il-code-generated-at-runtime-using-reflection-emit? – 2009-10-20 11:43:41

+0

我想真正调试到它不可视化的IL代码或我错过了什么? – jdehaan 2009-10-20 11:50:05

+0

或者你的意思是说其中的答案表明这是不可能的? – jdehaan 2009-10-20 11:52:20

回答

9

我终于找到了一种方法发现,我的问题的How to debug/break in codedom compiled code重复,这是不是很明显,我发现后要解决它。 bbmud给出了一个非常好的提示,让调试器正常工作,但并没有告诉如何进入代码。我引用添加一些组装包含我想在脚本中实现一个接口:

compilerParams.ReferencedAssemblies.Add(typeof(IScript).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); 

现在,当我考虑CSharpFriends是的IPlugin的实现,我可以通过铸造obj上面得到的界面:

IPlugin script = obj as IPlugin; 

然后调用接口方法或属性的调用与往常一样简单!添加的技巧

System.Diagnostics.Debugger.Break(); 

里面的脚本代码也很好,但它需要改变脚本。由于应用程序中的代码总是需要根据某种机制(具有属性或接口的反射)来了解脚本内部的哪些方法,因此使用两者都知道的接口对我来说是非常可接受的解决方案。

我希望它可以帮助别人。

+0

程序终止后,我正在努力处理临时文件。将TempFileCollection的第二个参数设置为false不是一个选项,因为再也不能调试了......我对这些文件进行单手处理(IDisposable实现),并且必须相应地处理AppDomain。 – jdehaan 2009-10-28 23:20:00

+0

也想到了Debugger.Break()。 :) – 2009-10-29 09:59:46

0

Visual Studio 2010在调试器中轻松处理这个问题。升级后,我感到很惊讶。我希望它有帮助。

相关问题