c#中这种行为的解释是什么?
本文关键字:解释 是什么 | 更新日期: 2023-09-27 18:16:32
考虑这个简单的控制台应用程序:
class Program
{
static void Main(string[] args)
{
var human = CreateHuman(args[0]);
Console.WriteLine("Created Human");
Console.ReadLine();
}
public static object CreateHuman(string association)
{
object human = null;
if (association == "is-a")
{
human = new IsAHuman();
}
else
{
human = new HasAHuman();
}
return human;
}
}
public class IsAHuman : Human
{
}
public class HasAHuman
{
public Human Human { get; set; }
}
Human
类在另一个程序集中,例如HumanAssembly.dll
。如果HumanAssembly.dll
存在于我们的控制台应用程序的bin
目录中,一切都会很好。正如我们所料,通过删除它,我们遇到了FileNotFoundException
。
我不明白这部分。注释human = new IsAHuman();
行,重新编译并删除HumanAssembly.dll
。在这种情况下,控制台应用程序不会抛出任何异常。
您正在看到JIT编译器的行为。及时赶到。直到最后可能的时刻,也就是在调用方法之前,才编译方法。由于您删除了实际构造Human对象的需要,因此没有留下强制抖动加载程序集的代码路径。所以你的程序不会崩溃。
对Human的最后一个引用是HashAHuman。人类的财产。你不用它。
预测抖动何时需要加载程序集是而不是在实践中那么直接。当您运行代码的发布版本时,很难进行推理。这通常会启用内置在抖动中的优化器,其核心优化策略之一是内联方法。要做到这一点,它需要在调用方法之前访问该方法。您需要一个额外的间接层,一个具有[MethodImpl(MethodImplOptions.NoInlining)]
属性的额外方法来阻止它进行窥视。这有点过分了,总是首先考虑插件架构,比如MEF。
这是你正在寻找的很好的解释。
CLR Loader
特别是在以下行-
这种按需加载类型(以及程序集和模块)的策略意味着程序中未使用的部分永远不会被引入内存。这也意味着运行中的应用程序经常会看到新的中包含的类型随时间加载的程序集和模块在执行期间需要这些文件。如果这不是行为你有两个选择。一种是简单地声明隐藏静态要保证的类型的字段在类型为时加载加载。另一种是显式地与加载器交互。
正如Bold行所说,如果你的代码没有执行特定的行,那么类型将不会被加载,即使代码没有被注释掉。
这里还有一个类似的答案,你可能也会感兴趣-
CLR如何加载dll ?