考虑这个简单的控制台应用程序:
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
。在这种情况下,控制台应用程序不会抛出任何异常。
我的猜测是CLR编译器区分是和有关联。换句话说,CLR试图找出并理解并可能加载类定义语句中存在的所有类型,但它可以在不知道其中的内容的情况下实例化一个类。但我不确定我的解释。
我找不到好的解释。这种行为有什么解释?
答案 0 :(得分:4)
您正在看到JIT编译器的行为。及时。一个方法直到最后一个可能的时刻才被编译,就在它被调用之前。由于您不需要实际构造Human对象,因此没有任何代码路径会强制抖动加载程序集。所以你的程序不会崩溃。
人类的最后一个参考是HashAHuman.Human属性。你不要用它。
预测抖动何时需要加载程序集 not 在实践中是直接的。当您运行代码的Release版本时,很难推理出来。通常enables the optimizer内置于抖动中,其核心优化策略之一是内联方法。为此,它需要在调用之前访问该方法。您需要一个额外的间接级别,一个具有[MethodImpl(MethodImplOptions.NoInlining)]
属性的额外方法可以阻止它进行查看。这有点偏向深入,总是首先考虑插件架构,就像MEF一样。
答案 1 :(得分:1)
以下是您正在寻找的内容的绝佳解释。
特别是以下几行 -
这种按需加载类型(和程序集和模块)的策略意味着程序中未使用的部分永远不会被带入 存储器即可。这也意味着正在运行的应用程序通常会看到新的 随着时间的推移加载的程序集和模块 执行期间需要这些文件。如果这不是行为 你想要,你有两个选择。一种是简单地声明隐藏的静态 当您的类型为时,将加载要保证的类型的字段 加载。另一种是明确地与加载器进行交互。
正如 Bold 行所示,如果您的代码没有执行特定的行,那么即使代码没有被注释掉,也不会加载类型。
以下是您可能也感兴趣的类似答案 -