Подтвердить что ты не робот

Отладка сгенерированной сборки .NET из созданного приложения

Короче говоря: как я могу отлаживать код, сгенерированный во время сеанса отладки в генерирующей программе? (см. код ниже)

У меня возникает следующая проблема: я хотел бы отлаживать динамически сгенерированный/скомпилированный код из приложения, которое его генерирует. Я представил упрощённый пример, чтобы прояснить это. Этот пример не требует отладки! Мое настоящее приложение генерирует еще много строк и кода, которые действительно оправдывают отладку, поверьте мне:-) Я хотел бы знать, есть ли способ отлаживать или поставить точку останова в HelloWorld. Вхождение вызова InvokeMethod не работает. Возможно, решение включает модификацию кода на сайтах вызовов в сгенерированную сборку.

Я уже рассмотрел многие вопросы (Отладка динамически загружаемой сборки в 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);
        }
    }
}
4b9b3361

Ответ 1

Я, наконец, нашел способ обходного пути после обнаружения того, что мой вопрос был дубликатом того, как отлаживать/прерывать скомпилированный код с кодовым кодом, что для меня не было очевидным. 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);

Теперь, когда я рассматриваю CSharpFriends как реализацию IPlugin, я могу получить интерфейс, IPlugin команду obj выше:

IPlugin script = obj as IPlugin;

Тогда отладка вызовов методам или свойствам интерфейса так же просто, как обычно! Трюк добавления

 System.Diagnostics.Debugger.Break();

внутри кода скрипта также хорошо работает, но ему нужно изменить сценарий. Поскольку код внутри приложения всегда должен знать, какие методы находятся внутри скрипта в соответствии с каким-либо механизмом (рефлексия с атрибутами или интерфейсами), использование интерфейса, известного для обоих, является для меня очень приемлемым решением.

Надеюсь, это поможет кому-то другому.

Ответ 2

Visual Studio 2010 осторожно обрабатывает этот отладчик. Я был удивлен этим после того, как я обновился. Надеюсь, это поможет.