The increasing popularity of software reuse has resulted in a new term, Component-Oriented Programming, that not only encompasses object-oriented programming, but also has built-in mechanisms facilitating code reuse. To understand the mechanisms provided by .NET to facilitate component-oriented programming, we need to have a look at the nature of classes and code reuse.
Code reuse in this discussion will refer to reuse at the class level as previously described. It can involve more than one class.
Classes often collaborate Objects of a class often collaborate with objects of other classes to accomplish their tasks. For example, in the Elevator simulation, the objects of the Building, People, Elevator, Button, and so on classes collaborate to run a full simulation.
Categories of classes A class can often be said to belong to the same category as another class. For example, one class might enable you to calculate the square root of a number and provide various logarithmic functions. Another class might enable you to calculate certain trigonometric expressions, such as sine and cosine. Both classes can be said to belong to a Math category.
Class libraries Collecting classes belonging to the same category into the same container makes it easier to browse through large numbers of classes. Such collections of classes are often referred to as class libraries.
Classes and resources Classes or class libraries often rely on various resources that cannot be regarded as computer programs. Examples of resources are images and sounds.
Classes and files Classes and class libraries exist inside the computer and, consequently, must have a physical existence (electrical signals in the memory and processor of the computer). Their dormant existence is in the form of files. When the classes are activated and their functionality used, they are compiled and executed in the main memory and processor of the computer.
The unit of reuse in .NET is called an assembly. For that reason, an assembly can be said to be a component. Any program in .NET and C# consists of one or more assemblies. We will see how the assembly accommodates for the nature of classes and their reuse to facilitate component-oriented programming. But first, we need to take a closer look at the assembly itself.
An assembly is a logical self-describing package. It consists of MSIL, metadata, and optional resources, such as graphical images. Any program written under .NET, whether it is a component for reuse only or a freestanding executable program, is an assembly.
An assembly can be viewed from two perspectives:
From the assembly developer's point of view, looking at the assembly from the inside at the detailed source code level.
From the assembly users point of view, he or she is looking at the assembly from the outside in search for suitable components to be reused in his or her current project.
Notice that in the compilation process shown in Figure 1.7 (see page 19), you can regard the output from all the language compilers to be assemblies.
An assembly is produced by the C# compiler, as shown shortly in Figure 2.5. The less important parts of this discussion have been dimmed in the figure, but they have been included so you can relate the concepts to the overall compilation and execution process.
Initially, the developer writes the C# source code (see 1 in Figure 2.5). Perhaps he or she wants to reuse the code from other already existing assemblies in the executable program. This is accomplished by instructing the compiler to include the relevant assemblies in the compilation process (see 2 in Figure 2.5). Depending on the programmer's preference, the compilation results in either a Portable Executable File (PE File with extension .exe) or a Dynamic Link Library File (DLL File with extension .dll). A PE file can be executed as is simply by executing it, but it can also be used as a component for reuse in other programs. On the other hand, a DLL file cannot be executed on its own. It is a component made for reuse only and can only be put into use if slotted into another application.
MSIL is generated during the compilation, and will be part of the assembly.
The compiler further emits a manifest consisting of metadata to represent the assembly. It holds descriptive information about the classes, methods, and resources exposed from within the assembly. This enables programmers to browse through the relevant details of each assembly, allowing him or her to judge whether it is suitable for reuse in his or her project. Each assembly might be dependent on other assemblies. The manifest specifies the assemblies on which its assembly depends. The latter are established in step 2 in Figure 2.5 and maintained in step 2 of Figure 2.6, which appears shortly. The connections illustrated with arrows are specified in the manifest.
An assembly might be dependent on other assemblies to provide its functionality, as mentioned earlier; this is specified in the manifest. But the manifest also indirectly connects its assembly to these assemblies. The term indirectly is used here because the connections provided by the manifest are of a descriptive nature.
Even though the assembly is based on separate files, it is one logic entity when looked at from the outside.
The manifest allows the runtime to expose classes and their methods to the assembly user (see Figure 2.6). The assembly user can then choose whichever functionality he or she needs to reuse from the assembly.
The decoupling of the logical entity seen from the outside and the physical elements (files) on the inside gives the developer of the assembly much more freedom in terms of the number of files needed, the sizes of these files, and their location.
We can now begin to appreciate the assembly as the unit of reuse in .NET. Through its self-describing abilities using metadata, it exposes the functionality it provides to its user and further specifies the classes and resources it needs to provide those services.
Let's return to the five points concerning the nature of classes and reuse and look at how assemblies and .NET deal with each of those points.
Re.1 Classes often collaborate Each class residing inside an .exe/.dll file can, through the accompanying metadata, expose its functionality and thereby resolve dependencies to other classes.
Re.2 Categories of classes It's easy to form different assemblies containing various categories of classes.
Re.3 Class libraries The container referred to in this point is an assembly in the .NET world. Utilizing the metadata provided in the manifest, it becomes easy to browse through classes, methods, and instance variables of the container (assembly).
Re.4 Classes and resources Simply by including the various resource files needed by the classes of an assembly, they are ready to be used.
Re.5 Classes and files As we have seen, the physical representation of the assembly is extremely flexible. The developer has great flexibility in terms of how many files to use and the content and location of each file. These choices do not affect the view and functionality provided to the assembly user.