Working With Assemblies, Modules, and Types

A .NET assembly is a .NET EXE or DLL that includes of one or more modules whose types are aggregated as one logical package. Modules are the highest level containers of all TypeNode objects. All non-nested types in the assembly are exposed directly via the module. Typically, an assembly has only one module. There are two exceptions: The first is when the assembly references .netmodule files that span the assembly over multiple physical files. This is typically—if there is anything typical about this—accomplished using the C# or VB.NET compiler's /addmodule option. The second is when the assembly linker al.exe or a similar tool is used to produce a single EXE or DLL that combines multiple modules into a single physical assembly file.

In the introspection model, AssemblyNode inherits from ModuleNode. The main module in the physical assembly is accessed directly through the AssemblyNode. The ModuleNode objects for other modules can be obtained through the AssemblyNode.ModuleReferences property or more explicitly with the GetNestedModule method. The ModuleNode.Types property provides the TypeNode objects for all of the types (classes, structures, and so on) contained in the module. The GetType method that takes two Identifier parameters can be used to obtain a type given its namespace name and type name.

[Important]Important

When the Types property and the GetType method are invoked on an AssemblyNode, they only return types in the main module. To properly support assemblies containing multiple modules, you may need to check the main module (the AssemblyNode) and all of the modules in the assembly's ModuleReferences collection when looking for a type.

There are many ways to obtain a reference to an AssemblyNode. These include:

  1. Navigate to the AssemblyNode from a child Node that you already have. For example, through a parameter passed to you by FxCop. Often, this means using the TypeNode.DeclaringModule property. Once you have the ModuleNode, you can use its ContainingAssembly property to get the AssemblyNode.

  2. Use the FrameworkAssemblies class to obtain references to a small number of frequently used assemblies through its Mscorlib, System, SystemConfiguration, SystemData, SystemWeb, and SystemWindowsForms static properties.

  3. Use the ModuleNode.ReferencedAssemblies to get to an assembly referenced by a module that you already have.

  4. Use the static AssemblyNode.GetAssembly method to obtain an AssemblyNode based on the assembly's path and filename on disk. Since other methods are typically more efficient and easier to use, this method is somewhat of a last resort.

The FrameworkTypes class provides commonly used TypeNode objects analogous to how FrameworkAssemblies provides commonly used AssemblyNode objects. The types are not limited to the .NET Base Class Library; they also include types from higher layers of the .NET Framework such as Windows Forms and ASP.NET. It includes over a hundred TypeNode objects, among them are Component, Enum, GenericList (which corresponds to List<T>), DataSet, Form, and String.

Sometimes, you want to know if a type implements an interface or has a specific certain base class in its inheritance hierarchy. This is equivalent to asking if the type is assignable to the interface or base class in question. For example:

bool descendsFromControl = myType.IsAssignableTo(FrameworkTypes.Control)

A special type, FrameworkTypes.Void, is used for return values of methods that do not return any value such as void methods in C# and Sub methods in VB.NET.

Unconstructed generic types, such as List<T>, have an IsGeneric property of true. The type parameters (here, T) are available through the TemplateParameters property. Constructed generic types, such as List<String> are considered to be "structural types" and are discussed in the next section.