C# CLR如何加载DLL?

C# CLR如何加载DLL?,c#,clr,C#,Clr,我的假设始终是CLR在启动应用程序域时加载了它所需的所有DLL。然而,我写了一个例子,让我质疑这个假设。我启动我的应用程序,查看加载了多少模块 Process[] ObjModulesList; ProcessModuleCollection ObjModulesOrig; //Get all modules inside the process ObjModulesList = Process.GetProcessesByName("MyProcessName"); // Populate

我的假设始终是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在做什么,它是如何加载这些东西的,以及它是通过什么逻辑进行加载的吗?

CLR会根据需要加载程序集。当您执行一个方法时,它会查看它在哪里(哪个模块等),如果没有加载,它会加载它

下面是关于CLR性能的讨论,并讨论了加载程序集:

当CLR实时(JIT)编译Start方法时,它需要加载该方法中引用的所有程序集。这意味着将加载异常处理程序中引用的所有程序集,即使在执行应用程序的大部分时间可能不需要它们


这是针对SilverLight的,但它确实讨论了CLR会发生什么。

每当创建相应的COM对象时,COM DLL都会按需加载。非COM DLL也可能出现这种情况。

以下内容摘自Don Box的优秀Essential.Net。(可用)
(而且,imho是任何专业.Net开发人员必须具备的条件)

CLR加载程序

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

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

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

例2。2.加载具有显式代码库的程序集

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") ;
  }
}
虽然按位置加载程序集有些有趣,但大多数程序集都是使用程序集解析器按名称加载的。程序集解析器使用由四部分组成的程序集名称来确定使用程序集加载程序将哪个底层文件加载到内存中。如中所示,此名称到位置解析过程考虑了多种因素,包括应用程序所在的目录、版本控制策略和其他配置详细信息(本章后面将讨论所有这些)

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

例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") ;
  }
}
foreach (AssemblyName asn in Assembly.GetExecutingAssembly().GetReferencedAssemblies())
{
    var asm = Assembly.Load(fn);
    // I've found get types does a good job of ensuring the types are loaded.
    asm.GetTypes();
}