In the .NET environment, assemblies
are the fundamental units
of development and deployment; although the various languages allow
the .NET programmer to work with elements as fine-grained as classes
or functions, these types must belong as part of an assembly in order
to be loaded and used. Consequently, the assembly is the core of the
component model in .NET.
The Assembly type is the
Reflection API object representing the assembly.
An assembly (either a .DLL or .EXE—to the CLR, there is no
difference) consists of one or more modules; most assemblies are in
fact single-module assemblies. (Multimodule assemblies are certainly
possible, but usually not necessary for most
developers' needs. As such, they are not discussed
here.) .NET programmers can use the object model in the
Assembly class to discover information about a
particular assembly—for example, an assembly knows the modules
contained within it, and each module knows the types defined and
bound to that module. Thus, for any random assembly, a .NET program
can enumerate each type defined inside that assembly. This is, in
fact, what the WinCV.exe sample program (see the
.NET SDK, in the \bin subdirectory) does. (The
ILDasm.exe application provides similar results,
but uses unmanaged APIs to view into an assembly, rather than
Reflection.)
The Assembly API can be broken into
two collections: those representing
operations against a particular assembly (indicated by a particular
Assembly instance), and those that work
independently of a particular instance—loading an assembly into
the CLR, for example.
The instance-specific methods of Assembly are, for
the most part, self-describing. The properties of
Assembly, in particular, are straightforward.
CodeBase describes the URL from which this
assembly was loaded, EntryPoint describes the
entry point (the Main( )) of the assembly, if it
has one, Evidence is the security information
regarding this particular assembly, and FullName
is the fully qualified (name, culture, version info, and public key
token) for this assembly. The remaining two properties are a bit more
obscure: GlobalAssemblyCache is a simple boolean
value indicating whether this assembly was loaded out of the global
assembly cache or not, and Location describes the
location of the manifest file (which may be in a different file if
this is a multimodule assembly). Note that as of the 1.1 .NET
release, a new property, ImageRuntimeVersion,
returns the version number of the CLR used to build the assembly;
when used against a 1.0-compiled assembly, it may return illegal
strings like "v1.x86ret" or
"retail" instead of the
1.1-documented "v1.1.4322".
Some instance methods of Assembly require a bit
more in the way of explanation. GetName( ) returns
the fully qualified name for this assembly; note that this is an
AssemblyName instance, rather than a string.
Because an Assembly is also a producer of custom
attribute types (such as AssemblyVersionAttribute
or AssemblyKeyFileAttribute),
Assembly also has the
GetCustomAttributes( ) method. In addition, the
IsDefined( ) method can be used to find a
particular attribute type defined in this assembly; it simply returns
a boolean true/false value, whereas GetCustomAttributes(
) returns the instance(s) of the attribute itself. A list
(an array of AssemblyName instances) of all
assemblies that this assembly references can be found by calling
GetReferencedAssemblies( ).
In addition to code, assemblies can contain arbitrary
"resources." (Here the term
"resource" means
"anything that's not
code.") These resources are contained as
.file references in the
assembly's manifest file and can be discovered from
an Assembly instance by calling
GetManifestResourceNames( ). Information about the
persistence scheme used for the resources is available via the
GetManifestResourceInfo( ). The actual resource
itself can be obtained by calling GetManifestResourceStream(
), which returns a System.IO.Stream
object containing or pointing to the file's
contents. In addition, a list of all files (both resources and code)
can be obtained by calling GetFiles( ), and a
particular file can be opened by calling GetFile(
).
An assembly consists of one or more modules; the list of modules
bound to this assembly are available via the GetModules(
) call. A particular module can be obtained as a
Module instance by calling GetModule(
) against the assembly. Because the CLR delays loading
modules until required, Assembly also provides the
GetLoadedModules( ) to list the modules of this
assembly that have been loaded into the CLR. Going the other
direction, the LoadModule( ) call forces the CLR
to load the given module name into memory, rather than waiting for
the usual on-demand loading policy of the CLR. Should a module-load
fail for some reason, the CLR signals event handlers bound against
the Assembly instance's
ModuleResolve event.
Frequently, a .NET programmer will not be interested in the modules
that comprise the assembly, only the types defined within it. Towards
that end, the Assembly type has a couple of
"shortcut" methods to get the
types. GetTypes( ) returns a list of all the types
defined in this assembly as an array of
System.Type references. GetType(
) returns a particular System.Type, or
optionally (depending on which overload is used) throws an exception
if the type cannot be found. Take note that the parameterless version
of GetType( ) is the inherited method from
System.Object; it returns the
System.Type reference for
Assembly, not any types defined within the
assembly itself. Note that the GetTypes( ) call
returns a list of all types defined in the assembly, even those
declared as private to the assembly (which normally should not be
seen by assembly consumers); to see a list of only the
"public" types, call
GetExportedTypes( ) instead.
Once a particular type within the assembly has been located, an
instance of that type can be created by calling
CreateInstance( ). This uses the system activator
(see System.Activator) to create an instance of
that type and hand it back as a generic object
reference. For example, calling object o =
typeof(Object).Assembly.CreateInstance("DateTime");
is a roundabout way to create an instance of a
System.DateTime; the
typeof(Object) returns the
System.Type for System.Object.
That type lives in the mscorlib.dll assembly, and
calling CreateInstance("DateTime") succeeds
because DateTime is defined within that assembly.
.NET programmers typically only use this method when building a
container application (such as ASP.NET) that will be creating
instances of objects not known at compile-time.
The Assembly type also contains a number of static
methods for use in referencing assemblies as a collective whole; for
example, the GetAssembly( ) call returns the
Assembly in which a particular
Type is defined. (Knowing this, we could change
the example in the last paragraph to read object o =
Assembly.GetAssembly(typeof(object)).CreateInstance("DateTime");,
which is a bit clearer if a bit longer.) Likewise, the
GetExecutingAssembly( ) returns the assembly in
which the current code is executing, and GetCallingAssembly(
) returns the assembly whose code called the methods in
this assembly. (These methods by themselves may seem less than
useful, until the idea of walking the call-stack, as Code Access
Security does, is considered.)
However, the two most important static methods on the
Assembly class by far are Load(
) and LoadFrom( ). Both load an assembly
into the CLR, but in drastically different ways. LoadFrom(
) is the simpler of the two, taking a filename and loading
it as an assembly into the CLR—no questions asked.
Load( ) goes through the assembly-load algorithm
and checks the private probe path and the Global Assembly Cache
before giving up on finding the assembly. (Note that if an
assembly-load request fails, the appropriate events on the containing
AppDomain instance are signaled.) In addition,
starting with the 1.1 release, these two are joined by a new method,
LoadFile( ), which will load an assembly specified
by a file location passed as a string.
public class Assembly : System.Security.IEvidenceFactory, ICustomAttributeProvider,
System.Runtime.Serialization.ISerializable {
// Public Instance Properties
public virtual string CodeBase{get; }
public virtual MethodInfo EntryPoint{get; }
public virtual string EscapedCodeBase{get; }
public virtual Evidence Evidence{get; }
// implements System.Security.IEvidenceFactory
public virtual string FullName{get; }
public bool GlobalAssemblyCache{get; }
public virtual string ImageRuntimeVersion{get; }
public virtual string Location{get; }
// Public Static Methods
public static string CreateQualifiedName(string assemblyName, string typeName);
public static Assembly GetAssembly(Type type);
public static Assembly GetCallingAssembly( );
public static Assembly GetEntryAssembly( );
public static Assembly GetExecutingAssembly( );
public static Assembly Load(AssemblyName assemblyRef);
public static Assembly Load(AssemblyName assemblyRef, System.Security.Policy.Evidence assemblySecurity);
public static Assembly Load(byte[ ] rawAssembly);
public static Assembly Load(byte[ ] rawAssembly, byte[ ] rawSymbolStore);
public static Assembly Load(byte[ ] rawAssembly, byte[ ] rawSymbolStore,
System.Security.Policy.Evidence securityEvidence);
public static Assembly Load(string assemblyString);
public static Assembly Load(string assemblyString, System.Security.Policy.Evidence assemblySecurity);
public static Assembly LoadFile(string path);
public static Assembly LoadFile(string path, System.Security.Policy.Evidence securityEvidence);
public static Assembly LoadFrom(string assemblyFile);
public static Assembly LoadFrom(string assemblyFile, System.Security.Policy.Evidence securityEvidence);
public static Assembly LoadFrom(string assemblyFile, System.Security.Policy.Evidence securityEvidence,
byte[ ] hashValue, System.Configuration.Assemblies.AssemblyHashAlgorithm hashAlgorithm);
public static Assembly LoadWithPartialName(string partialName);
public static Assembly LoadWithPartialName(string partialName, System.Security.Policy.Evidence securityEvidence);
// Public Instance Methods
public object CreateInstance(string typeName);
public object CreateInstance(string typeName, bool ignoreCase);
public object CreateInstance(string typeName, bool ignoreCase, BindingFlags bindingAttr,
Binder binder, object[ ] args, System.Globalization.CultureInfo culture, object[ ] activationAttributes);
public virtual object[ ] GetCustomAttributes(bool inherit);
// implements ICustomAttributeProvider
public virtual object[ ] GetCustomAttributes(Type attributeType, bool inherit)
// implements ICustomAttributeProvider
public virtual Type[ ] GetExportedTypes( );
public virtual FileStream GetFile(string name);
public virtual FileStream[ ] GetFiles( );
public virtual FileStream[ ] GetFiles(bool getResourceModules);
public Module[ ] GetLoadedModules( );
public Module[ ] GetLoadedModules(bool getResourceModules);
public virtual ManifestResourceInfo GetManifestResourceInfo(string resourceName);
public virtual string[ ] GetManifestResourceNames( );
public virtual Stream GetManifestResourceStream(string name);
public virtual Stream GetManifestResourceStream(Type type, string name);
public Module GetModule(string name);
public Module[ ] GetModules( );
public Module[ ] GetModules(bool getResourceModules);
public virtual AssemblyName GetName( );
public virtual AssemblyName GetName(bool copiedName);
public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
// implements ISerializable
public AssemblyName[ ] GetReferencedAssemblies( );
public Assembly GetSatelliteAssembly(System.Globalization.CultureInfo culture);
public Assembly GetSatelliteAssembly(System.Globalization.CultureInfo culture, Version version);
public virtual Type GetType(string name);
public virtual Type GetType(string name, bool throwOnError);
public Type GetType(string name, bool throwOnError, bool ignoreCase);
public virtual Type[ ] GetTypes( );
public virtual bool IsDefined(Type attributeType, bool inherit);
// implements ICustomAttributeProvider
public Module LoadModule(string moduleName, byte[ ] rawModule);
public Module LoadModule(string moduleName, byte[ ] rawModule, byte[ ] rawSymbolStore);
public override string ToString( );
// overrides object
// Events
public event ModuleResolveEventHandler ModuleResolve;
}