5.6.3 True .NET components

In .NET, all managed code is contained in assemblies, which are independent, versioned entities that explicitly declare their dependencies. A .NET executable file is an assembly with an entry point, whereas a .NET shared library is an assembly without such an entry point. An assembly may consist of one or many modules, each of which can be written in separate languages targeting the CLR. Assemblies can be private or shared; shared assemblies are placed in the Global Assembly Cache for use by other assemblies (Troelsen 2007:347).

Assemblies typically contain only managed code, but may also be “mixed,” meaning that they contain both managed and unmanaged code. Such assemblies can be produced by Microsoft’s C++ compiler. A C++ class may be written using both managed and unmanaged code, making it particularly easy for managed code to interoperate with unmanaged code, without the use of P/Invoke or the COM interoperability services.

Unlike an OSGi bundle, there is no metadata on the level of an assembly that declares which types should be visible to other assemblies. .NET does provide such metadata, but as normal access specifiers. In C#, types can either be declared as internal or public. Internal types, which is the default access specifier if none is given explicitly, are not visible outside of the defining assembly.

An assembly cannot, unlike an OSGi bundle, be loaded and unloaded dynamically. However, assemblies are contained in so-called “app domains,” which do have this feature. If desired, an app domain can house only one assembly, in effect making it possible to load and unload singular assemblies.

With assemblies, .NET features true components as part of the core platform.