草庐IT

c# - CLR 如何加载 DLL?

coder 2024-05-22 原文

我的假设始终是 CLR 在应用程序域启动时加载了它需要的所有 DLL。但是,我写了一个例子,让我质疑这个假设。我启动我的应用程序并检查加载了多少模块。

Process[] ObjModulesList;
ProcessModuleCollection ObjModulesOrig;

//Get all modules inside the process
ObjModulesList = Process.GetProcessesByName("MyProcessName");
// Populate the module collection.
ObjModulesOrig = ObjModulesList[0].Modules;

Console.WriteLine(ObjModulesOrig.Count.ToString());

然后我重复完全相同的代码,我的计数不同。附加的 DLL 是 C:\WINNT\system32\version.dll。

我真的很困惑为什么计数会不同。

有人可以详细说明 CLR 正在做什么以及它如何加载这些东西,以及它是按照什么逻辑这样做的?

最佳答案

以下复制自Don Box的优秀基本.Net . (可用 here)
(而且,恕我直言,任何专业的 .Net 开发人员都必须拥有)

CLR 加载器

CLR 加载器负责加载和初始化程序集、模块、资源和类型。 CLR 加载器尽可能少地加载和初始化。与 Win32 加载器不同,CLR 加载器不会解析并自动加载从属模块(或程序集)。
相反,从属部分仅在实际需要时才按需加载(与 Visual C++ 6.0 的延迟加载功能一样)。这不仅加快了程序初始化时间,而且减少了运行程序消耗的资源量。
在 CLR 中,加载通常由基于类型的即时 (JIT) 编译器触发。当 JIT 编译器尝试将方法体从 CIL 转换为机器代码时,它需要访问声明类型的类型定义以及类型字段的类型定义。此外,JIT 编译器还需要访问被 JIT 编译的方法的任何局部变量或参数使用的类型定义。加载类型意味着加载包含类型定义的程序集和模块。
这种按需加载类型(以及程序集和模块)的策略意味着程序中未被使用的部分永远不会被带入内存。这也意味着正在运行的应用程序经常会看到随着时间的推移加载新的程序集和模块,因为在执行期间需要这些文件中包含的类型。如果这不是您想要的行为,您有两种选择。一种是简单地声明要与加载器显式交互的类型的隐藏静态字段。

加载器通常代表您隐式地完成它的工作。开发人员可以通过程序集加载器显式地与加载器交互。程序集加载器通过 LoadFrom 向开发人员公开。 System.Reflection.Assembly 上的静态方法类(class)。此方法接受 CODEBASE 字符串,该字符串可以是文件系统路径,也可以是标识包含程序集 list 的模块的统一资源定位符 (URL)。如果找不到指定的文件,加载器会抛出 System.FileNotFoundException异常(exception)。如果可以找到指定的文件但不是包含程序集 list 的 CLR 模块,则加载程序将抛出 System.BadImageFormatException异常(exception)。最后,如果 CODEBASE 是使用除 file: 之外的方案的 URL ,调用者必须具有 WebPermission 访问权限,否则会出现 System.SecurityException抛出异常。此外,使用除 file: 之外的协议(protocol)的 URL 中的程序集在加载之前首先下载到下载缓存。

list 2.2 显示了一个简单的 C# 程序,它加载位于 file://C:/usr/bin/xyzzy.dll 的程序集。然后创建一个名为 AcmeCorp.LOB.Customer 的包含类型的实例.在这个例子中,调用者提供的只是程序集的物理位置。
当程序以这种方式使用程序集加载器时,CLR 会忽略程序集的四部分名称,包括其版本号。

示例 2. 2. 使用显式 CODEBASE 加载程序集

using System;
using System.Reflection;
public class Utilities {
  public static Object LoadCustomerType() {
    Assembly a = Assembly.LoadFrom(
                    "file: //C:/usr/bin/xyzzy. dll") ;
    return a.CreateInstance("AcmeCorp.LOB.Customer") ;
  }
}

尽管按位置加载程序集有些有趣,但大多数程序集是使用程序集解析器按名称加载的。程序集解析器使用由四部分组成的程序集名称来确定使用程序集加载器将哪个底层文件加载到内存中。如Figure 2.9所示,此名称到位置解析过程考虑了多种因素,包括应用程序所在的目录、版本控制策略和其他配置细节(本章稍后将讨论所有这些)。

程序集解析器通过 Load 向开发人员公开。 System.Reflection.Assembly的方法类(class)。如 list 2.3 所示,该方法接受由四部分组成的程序集名称(作为字符串或作为 AssemblyName 引用),并且表面上看起来类似于程序集加载器公开的 LoadFrom 方法。这种相似性只是肤浅的,因为 Load 方法首先使用程序集解析器通过一系列相当复杂的操作来查找合适的文件。这些操作中的第一个是应用版本策略来准确确定应加载所需程序集的哪个版本。

例 2.3。使用装配解析器加载装配
using System;
using System.Reflection;
public class Utilities {
  public static Object LoadCustomerType() {
    Assembly a = Assembly.Load(
      "xyzzy, Version=1. 2. 3.4, " +
      "Culture=neutral, PublicKeyToken=9a33f27632997fcc") ;
    return a.CreateInstance("AcmeCorp.LOB.Customer") ;
  }
}

关于c# - CLR 如何加载 DLL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2967164/

有关c# - CLR 如何加载 DLL?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

随机推荐