C# 调试.net core 2.0中动态加载程序集的代码

C# 调试.net core 2.0中动态加载程序集的代码,c#,.net,.net-core,C#,.net,.net Core,我有一个.net core 2.0控制台应用程序,可执行以下操作(简化): 当我调试代码时,它会按预期逐步进入MyType.Execute() 但是,如果使用以下代码加载程序集: var path = new FileInfo(Assembly.GetExecutingAssembly().Location); var a = Assembly.LoadFile(Path.Combine(path.DirectoryName, "MyAssembly.dll")); 代码仍然有效,但调试时我无

我有一个.net core 2.0控制台应用程序,可执行以下操作(简化):

当我调试代码时,它会按预期逐步进入
MyType.Execute()

但是,如果使用以下代码加载程序集:

var path = new FileInfo(Assembly.GetExecutingAssembly().Location);
var a = Assembly.LoadFile(Path.Combine(path.DirectoryName, "MyAssembly.dll"));
代码仍然有效,但调试时我无法进入
MyType.Execute()

你知道为什么/怎么了吗?

你检查了选项了吗

仅启用我的代码

仅限(“我的代码”),忽略系统代码和其他 优化的或没有调试符号的。调试器将显示并单步执行用户代码


可能应该取消选中它?

这可能是由于应用程序无法找到与
MyAssembly
程序集关联的PDB文件,如其中一条注释中所述。但是,要使调试工作正常,PDB文件似乎不需要与程序集位于同一文件夹中

为了检查是否加载了符号,请在调用
Assembly.LoadFile()
后在行中放置一个断点,然后打开Modules窗口(可以在Visual Studio的调试\窗口菜单中找到)。在此窗口中,找到
MyAssembly
assembly并验证符号状态列中的值。如果原因是缺少PDB,则值将为“找不到或无法打开PDB文件”。您还可以使用该窗口查看调试器试图在何处查找符号文件

调试器在多个位置查找PDB文件,如下所述:

根据文章,PDB文件的默认位置为:

  • 在程序集本身内部指定的位置(编译程序集时由链接器放置在该位置)
  • 动态加载的程序集所在的文件夹
  • 本地符号缓存文件夹
  • Internet、网络或本地符号服务器
  • 我想在你的情况下,应该考虑提到的第一个或第二个地点

    另一个需要注意的重要事项是,PDB必须与程序集完全匹配,因此在重新编译程序集之后,还应该更新PDB文件以匹配新版本

    如果PDB文件与程序集匹配,并且驻留在上述位置之一,则应该能够调试代码


    可能还有其他原因,这与使用.NET Core的事实没有直接关系,但我认为正确的PDB加载可能值得验证。

    我同意Lukasz和Alexan的答案。如果您已经检查了这些,但它不起作用,那么代码示例不同的原因可能是它们没有加载相同的程序集


    执行程序集和条目程序集并不总是相同的程序集,因此路径可能不同。也可能是加载了程序集的另一个版本,例如从GAC加载。使用VisualStudio中的“模块”窗口,可以查看加载了哪个dll。如果存在正确的PDB,并且仅禁用了“我的代码”,则您应该能够单步执行该操作。

    有一个“Assembly.Load”覆盖,它将PDB数据作为参数。您需要显式加载调试符号

    查看此SO帖子:

    也可以在MSDN上查看此内容:


    希望这对您有所帮助

    如果您使用
    Assembly.LoadFile
    方式,代码将不会编译

    我已经在Visual studio 2017社区中创建了一个示例项目,通过使用
    assembly.LoadFile
    assembly.Load
    两种方式,我能够从动态汇编中逐步实现一个函数。我没有使用您的代码,因为它不是编译的,但我将提供一个解决方案,我认为您将解决您的问题

    以下是解决方案: 完整的工作解决方案在这里

    基本上我可以用下面的代码进行调试。您应该在调用方法时按f11

    var assemlies = Assembly.GetEntryAssembly().GetReferencedAssemblies();
            var assemblyName = "";
            foreach (var item in assemlies)
            {
                if (item.Name == "RefProj")
                    assemblyName = item.Name;
    
            }
            var path = new FileInfo(Assembly.GetExecutingAssembly().Location);
            var a = Assembly.LoadFile(Path.Combine($@"{path}\..\..\..\..\..\RefProj\bin\Debug\netstandard2.0", "RefProj.dll"));
            var t = a.GetType("RefProj.Class1");
    
            var i = Activator.CreateInstance(t);
            MethodInfo mi = t.GetMethod("get1");
            mi.Invoke(i, null);
    

    也许我的代码选项应该被禁用?您需要确保.pdb文件与正在加载的dll位于同一位置。VisualStudio随后将加载该数据并允许它在断点处停止。谢谢你的回答。在我的例子中,模块不幸加载。所谓“模块加载”,您是指模块窗口中显示的动态加载程序集加载的符号,对吗?是的,很抱歉,我的意思是这样的。可能尝试在程序实例的调试菜单上使用“附加到进程”,然后尝试选择所有托管代码类型?(即CoreCLR和4.x)但这仅在从字节数组加载时才需要,或者我错了吗?您可以将任何文件作为字节数组加载
    System.IO.File.ReadAllBytes(字符串路径)
    --对吗?@MathijsFlietstra:My posts解释了为什么这两个示例的行为可能不同。从这个意义上说,我相信我的回答除了只知道什么是错的之外是有用的,卢卡斯的回答已经涵盖了这一点。
    var assemlies = Assembly.GetEntryAssembly().GetReferencedAssemblies();
            var assemblyName = "";
            foreach (var item in assemlies)
            {
                if (item.Name == "RefProj")
                    assemblyName = item.Name;
    
            }
            var path = new FileInfo(Assembly.GetExecutingAssembly().Location);
            var a = Assembly.LoadFile(Path.Combine($@"{path}\..\..\..\..\..\RefProj\bin\Debug\netstandard2.0", "RefProj.dll"));
            var t = a.GetType("RefProj.Class1");
    
            var i = Activator.CreateInstance(t);
            MethodInfo mi = t.GetMethod("get1");
            mi.Invoke(i, null);