从生成它的应用程序中调试生成.NET程序集它的、应用程序、程序、NET

2023-09-03 09:42:26 作者:旧了時光ペ涼了心

在短期的问题:我如何调试的生成程序在调试会话过程中产生的code? (见下文code)

我面临着以下问题:我想调试到动态生成/编译code从产生它的应用程序。我提供了一个过于简单的例子来阐明它。这个例子并不需要调试!我真正的应用程序产生更多的线和code,真正证明调试,相信我:-)我想知道是否有一种方法来调试或放一个断点的HelloWorld 。踏入的InvokeMethod不能正常工作。也许一个解决方案包括code修改在调用点到生成的程序集。

我看了一下许多问题已经(http://stackoverflow.com/questions/1295807/debug-dynamically-loaded-assembly-in-visual-studio-net举例来说),但没有一个解决问题有帮助(如果有解呢?)

我花了code从http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=118作为基础和固定的已经过时的电话。除了这个,我产生的即时装配在内存中调用运作良好。我产生明确的装配与调试信息,是什么给了我希望:为什么如果调试是不可能会有选项

 使用系统;
使用System.Text;
使用System.IO;
使用Microsoft.CSharp;
使用系统codeDom.Compiler。
使用的System.Reflection;

命名空间DynamicAssembly
{
    类CreateCompileExecute
    {
        [STAThread]
        静态无效的主要(字串[] args)
        {
            //创建一个文本文件来存储新类
            StringBuilder的建设者=新的StringBuilder();
            builder.AppendLine(使用系统;);
            builder.AppendLine(命名空间CSharpFriendsRocks);
            builder.AppendLine({);
            builder.AppendLine(级CSharpFriends);
            builder.AppendLine({);
            builder.AppendLine(公共CSharpFriends(){+
                Console.WriteLine(\的CSharpFriends型构造\);});
            builder.AppendLine(公共无效的HelloWorld(){+
                Console.WriteLine(\的Hello World  -  CSharpFriends.Com岩石\);});
            builder.AppendLine(});
            builder.AppendLine(});

            //创建C#编译器
            CSHARP codeProvider csCompiler =新CSHARP codeProvider();

            //输入PARAMS编译器
            CompilerParameters compilerParams =新CompilerParameters();
            compilerParams.OutputAssembly =CSharpFriends.dll;
            compilerParams.GenerateInMemory = TRUE;
            compilerParams.IncludeDebugInformation = TRUE;
            compilerParams.ReferencedAssemblies.Add(system.dll中);
            compilerParams.GenerateExecutable = FALSE; //生成的DLL

            //运行编译器和生成程序集
            CompilerResults结果= csCompiler.CompileAssemblyFromSource(
                compilerParams,builder.ToString());

            //加载生成的程序集到ApplicationDomain中
            大会ASM = results.CompiledAssembly;
            类型t = asm.GetType(CSharpFriendsRocks.CSharpFriends);

            //的BindingFlags枚举指定控制标志结合和
            //在其中寻找成员和类型,通过反射的方式。
            //下面指定绑定类型的访问控制
            的BindingFlags bflags = BindingFlags.DeclaredOnly | BindingFlags.Public
                        | BindingFlags.NonPublic可| BindingFlags.Instance;

            //构造类型的实例,并调用成员方法
            obj对象= t.InvokeMember(HelloWorld的,bflags |
                BindingFlags.CreateInstance,NULL,NULL,NULL);

            //调用方法
            t.InvokeMember(HelloWorld的,bflags | BindingFlags.InvokeMethod,
                    空,OBJ,NULL);
        }
    }
}
 

解决方案

我终于找到了一种方法发现,我的问题是的如何调试/休息在codeDOM编译code ,这是不是明显对我来说找到。 bbmud给出了一个很好的提示在那里得到的调试器正常工作,但并没有告诉如何进入code。我想补充一个参考一些组件包含了我想要的脚本来实现一个接口:

  compilerParams.ReferencedAssemblies.Add(typeof运算(的iScript).Assembly.Location);
compilerParams.GenerateExecutable = FALSE; //生成的DLL

//如果要调试,这是需要...
compilerParams.GenerateInMemory = FALSE;
compilerParams.TempFiles =新TempFileCollection(环境。
      GetEnvironmentVariable(TEMP),真正的);
 
应用 Eclipse 远程调试 Java 应用程序

现在,当我考虑 CSharpFriends IPlugin 的实现,我可以通过铸造获取接口的 OBJ 上面的:

  IPlugin脚本= OBJ为IPlugin;
 

然后调试调用接口方法或属性是像往常一样简单!加入的伎俩

  System.Diagnostics.Debugger.Break();
 

里面的脚本code也工作得很好,但它需要的脚本变化。随着应用程序内的code总是需要知道什么样的方法是在脚本中根据一些机构(反思与属性或接口),利用这两个对我来说是非常可以接受的解决方案闻名的接口。

我希望它可以帮助别人。

The question in short: How can I debug the code generated during a debugging session on the generating program? (see code below)

I am facing the following issue: I would like to debug into dynamically generated/compiled code from the application that generates it. I provided an oversimplified example to clarify it. This example doesn't need debugging! My real app generates many more lines and code that really justify debugging, believe me :-) I would like to know if there is a way to debug or put a breakpoint at HelloWorld. Stepping into the InvokeMethod call doesn't work. Maybe a solution involves code modification at the call sites to the generated assembly.

I had a look at many questions already (http://stackoverflow.com/questions/1295807/debug-dynamically-loaded-assembly-in-visual-studio-net for example) but none was helpful in solving the problem (if solvable at all?)

I took code from http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=118 as a base and fixed the obsoleted calls. Beside this I generated the assembly on-the-fly in memory and the calls are working well. I generated explicitly an assembly with Debug information, what gives me hope: why would there be the option if debugging is not possible?

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

解决方案

I finally found a way to workaround it after discovering that my question was a duplicate of How to debug/break in codedom compiled code, which was not obvious for me to find. bbmud gives a very good hint in there to get the debugger working correctly, but doesn't tell how to get into the code. I add a reference to some assembly containing an interface that I want to implement in the scripts:

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

Now when I consider CSharpFriends being an implementation of IPlugin, I can get the interface by casting the obj above:

IPlugin script = obj as IPlugin;

Then debugging calls to interface methods or properties is as easy as usual! The trick of adding

 System.Diagnostics.Debugger.Break();

inside the script code also works well but it needs change to the script. As the code inside the application always needs to know what kind of methods are inside the script according to some mechanism (reflexion with attributes or interfaces), using an interface known by both is a very acceptable solution for me.

I hope it helps somebody else.

 
精彩推荐
图片推荐