在C#中解释这种行为的原因是什么?

时间:2014-08-05 10:37:52

标签: c# types clr

考虑这个简单的控制台应用程序:

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试图找出并理解并可能加载类定义语句中存在的所有类型,但它可以在不知道其中的内容的情况下实例化一个类。但我不确定我的解释。

我找不到好的解释。这种行为有什么解释?

2 个答案:

答案 0 :(得分:4)

您正在看到JIT编译器的行为。及时。一个方法直到最后一个可能的时刻才被编译,就在它被调用之前。由于您不需要实际构造Human对象,因此没有任何代码路径会强制抖动加载程序集。所以你的程序不会崩溃。

人类的最后一个参考是HashAHuman.Human属性。你不要用它。

预测抖动何时需要加载程序集 not 在实践中是直接的。当您运行代码的Release版本时,很难推理出来。通常enables the optimizer内置于抖动中,其核心优化策略之一是内联方法。为此,它需要在调用之前访问该方法。您需要一个额外的间接级别,一个具有[MethodImpl(MethodImplOptions.NoInlining)]属性的额外方法可以阻止它进行查看。这有点偏向深入,总是首先考虑插件架构,就像MEF一样。

答案 1 :(得分:1)

以下是您正在寻找的内容的绝佳解释。

The CLR Loader

特别是以下几行 -

  

这种按需加载类型(和程序集和模块)的策略意味着程序中未使用的部分永远不会被带入   存储器即可。这也意味着正在运行的应用程序通常会看到新的   随着时间的推移加载的程序集和模块   执行期间需要这些文件。如果这不是行为   你想要,你有两个选择。一种是简单地声明隐藏的静态   当您的类型为时,将加载要保证的类型的字段   加载。另一种是明确地与加载器进行交互。

正如 Bold 行所示,如果您的代码没有执行特定的行,那么即使代码没有被注释掉,也不会加载类型。

以下是您可能也感兴趣的类似答案 -

How are DLLs loaded by the CLR?