2009-10-20 9 views
11

Krótko mówiąc: Jak mogę debugować kod wygenerowany podczas sesji debugowania w programie generującym? (patrz kod poniżej)Debugowanie wygenerowanego zestawu .NET z poziomu aplikacji, która je wygenerowała.

Mam do czynienia z następującym problemem: Chciałbym debugować dynamicznie generowane/skompilowany kod z aplikacji, która go generuje. Podałem uproszczony przykład, aby to wyjaśnić. Ten przykład nie wymaga debugowania! Moja prawdziwa aplikacja generuje o wiele więcej wierszy i kodu, które naprawdę usprawiedliwiają debugowanie, uwierz mi :-) Chciałbym wiedzieć, czy istnieje sposób debugowania lub umieszczenia punktu przerwania na HelloWorld. Wejście do wywołania InvokeMethod nie działa. Być może rozwiązanie polega na modyfikacji kodu w miejscu połączenia z wygenerowanym zespołem.

musiałem spojrzeć na wiele pytań już (Debug dynamically loaded assembly in Visual Studio .NET na przykład), ale żaden nie był pomocny w rozwiązaniu problemu (jeśli rozwiązywalne w ogóle?)

wziąłem kod z http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=118 jako baza i stałe połączenia przestarzałe. Oprócz tego wygenerowałem zestaw w locie w pamięci, a połączenia działają dobrze. Wygenerowałem jawnie zestaw z informacjami Debugowania, co daje mi nadzieję: dlaczego byłaby opcja, jeśli debugowanie nie jest możliwe?

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

Czy widziałeś http://stackoverflow.com/questions/321203/how-do-i-debug-il-code-generated-at-runtime-using-reflection-emit? –

+0

Chcę naprawdę debugować, nie wizualizować kodu IL, czy też coś mi umknęło? – jdehaan

+0

Czy masz na myśli odpowiedź, która stwierdza, że ​​nie jest to możliwe? – jdehaan

Odpowiedz

9

końcu znaleźli sposób na obejście tego problemu to po odkryciu, że moje pytanie było duplikatem How to debug/break in codedom compiled code, co nie było oczywiste dla mnie znaleźć. bbmud daje bardzo dobrą wskazówkę, aby debugger działał poprawnie, ale nie mówi, jak dostać się do kodu. I dodać odwołanie do jakiegoś zespołu zawierający interfejs, który chcę wdrożyć w skryptach:

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

Teraz kiedy uważam CSharpFriends jest implementacja IPlugin, mogę interfejs oddając obj powyżej:

IPlugin script = obj as IPlugin; 

Następnie debugowanie wywołań do metod interfejsu lub właściwości jest tak proste, jak zwykle! Sposób na dodanie kodu wewnątrz skryptu również działa dobrze, ale wymaga zmiany w skrypcie. Ponieważ kod wewnątrz aplikacji zawsze musi wiedzieć, jakie metody znajdują się w skrypcie zgodnie z pewnym mechanizmem (reflexion z atrybutami lub interfejsami), użycie interfejsu znanego obu jest dla mnie bardzo akceptowalnym rozwiązaniem.

Mam nadzieję, że pomoże to komuś innemu.

+0

Mam problem z plikami tymczasowymi pozostającymi na dysku po zakończeniu programu. Ustawienie 2. parametru TempFileCollection na wartość false nie jest opcją, ponieważ debugowanie nie jest już możliwe ... Wykonuję zbędne usuwanie danych (wdrożenie IDisposable) plików i muszę odpowiednio obsługiwać AppDomains. – jdehaan

+0

Myśli również o funkcji Debugger.Break(). :) –

0

Visual Studio 2010 obsługuje to delikatnie w debugerze. Zaskoczyło mnie to po aktualizacji. Mam nadzieję, że to pomoże.

Powiązane problemy