The most basic element that reflection deals with is the Type class. This class represents the metadata for each type declaration in an application (both predefined and user-defined types).
Types contain members, which include constructors, fields, properties, events, and methods. In addition, types may contain nested types, which exist within the scope of an outer type and are typically used as helper classes. Types are grouped into modules, which are, in turn, contained within assemblies.
Assemblies are the logical equivalent of DLLs in Win32 and the basic unit of deployment, versioning, and reuse for types. In addition, assemblies create a security, visibility, and scope resolution boundary for types (for more information, see Chapter 12).
A module is a physical file such as a DLL, an EXE, or a resource (such as GIFs or JPGs). While it isn't common practice, an assembly can be composed of multiple modules, allowing you to control application working set size, use multiple languages within one assembly, and share a module across multiple assemblies.
From the perspective of reflection, an AppDomain is the root of the type hierarchy and serves as the container for assemblies and types when they are loaded into memory at runtime. A helpful way to think about an AppDomain is to view it as the logical equivalent of a process in a Win32 application.
AppDomains provide isolation, creating a hard boundary for managed code just like the process boundary under Win32. Similar to processes, AppDomains can be started and stopped independently, and application faults take down only the AppDomain the fault occurs in, not the process hosting the AppDomain.