假设我在以下程序集中有以下类型:
程序集 1:
public struct DependencyStruct { }
public class DependencyClass { }
程序集 2:
public class UsingDependency
{
private DependencyStruct m_DependencyStruct; // having this will field will cause the loading of the DependencyStruct type (thus will cause an assembly binding request).
private DependencyClass m_DependencyClass; // having this field will **not** cause the loading of the DependencyClass type.
}
程序集 3(可执行)
public class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.LoadFrom("Assembly2.dll");
Type[] types = assembly.GetTypes();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
}
}
当我运行以下代码时,我将在程序集数组中找到 Assembly2 和 Assembly1。
如果我注释掉 m_DependencyStruct 声明,我将在程序集数组中只找到 Assembly2。
请注意,我没有在此代码中创建任何实例,只是加载类型。
我的问题是:
为什么具有值类型字段会导致 CLR 加载整个类型(与具有延迟加载的引用类型相反)?
有没有办法延迟值类型的加载?使用
Lazy<DependencyStruct> m_LazyDependencyStruct
或者创建另一个包装器类会起作用,但我很好奇是否有另一种方法可以在不更改实际类型的情况下执行此操作。
谢谢!
最佳答案
这很难确定,CLR 中加载类型的代码是一大堆复杂的 C++ 代码。我看到在 MethodTableBuilder::InitializeFieldDescs() 方法中完成的一件事是它还计算类中字段的偏移量。
这需要知道每个字段需要多少存储空间。这对于引用类型的字段来说当然很简单,它只是一个指针的大小。但对于值类型的字段,它需要加载字段的类型,根据需要递归通过其字段来计算它们的大小。这当然会产生副作用,您会看到包含值类型的程序集也已加载。
只是一个有根据的猜测。您可以查看SSCLI20 发行版中的class.cpp 源代码文件自己查找。强大的实现细节,确保您永远不会关心这个。
关于c# - 为什么加载包含值类型字段的类会强制 CLR 加载该值类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23045151/