Dividing a Single C# Program into Multiple Assemblies

By John Paul Mueller, Bill Sempf, Chuck Sphar

In Visual Studio, and in C#, Visual Basic .NET, and the other .NET languages, one project equals one compiled module — otherwise known as an assembly in .NET. The words module and assembly have somewhat different technical meanings, but only to advanced programmers.

Executable or library?

  • Executable (.EXE): A program in its own right that contains a Main() method. You can double-click a .EXE file in Windows Explorer, for example, and cause it to run. Executable assemblies often use supporting code from libraries in other assemblies.
  • Class library (.DLLstrong>): A compiled library of functionality that can be used by other programs. Every program needs System classes. Libraries are housed in DLL assemblies.

Libraries aren’t executable — you can’t make them run directly. Instead, you must call their code from an executable or another library. The Common Language Runtime (CLR), which runs C# programs, loads library assemblies into memory as needed.

The important concept to know is that you can easily write your own class libraries.

Assemblies

Assemblies, which are the compiled versions of individual projects, contain the project’s code in a special format, along with a bunch of metadata, or detailed information about the classes in the assembly.

This section introduces assemblies because they round out your understanding of the C# build process — and they come into play in the discussion of namespaces and access keywords such as protected and internal. Assemblies also play a big part in understanding class libraries.

The C# compiler converts the project’s C# code to Common Intermediate Language (usually called IL) that’s stored in the appropriate type of assembly file. IL resembles assembly language (one step beyond the 1s and 0s used in machine language) that hardcore programmers have used for decades to get down “close to the metal” because their higher-level languages couldn’t do what they needed or the compilers couldn’t produce the most efficient code possible.

One major consequence of compiling from .NET to IL, regardless of language, is that a program can use assemblies written in different languages. For example, a C# program can call methods in an assembly originally written in Visual Basic or C++ or the C# program can subclass a VB class.

Executables

You can run executable assemblies in a variety of ways:

  • Run them in Visual Studio: Choose Debug→  Start Debugging (F5) or Debug→  Start without Debugging (Ctrl+F5).
  • Double-click the assembly file (.EXE) in Windows Explorer.
  • Right-click the file in Windows Explorer and choose Run or Open from the pop-up menu.
  • Type the assembly’s name (and path) into a console window.
  • If the program takes arguments, such as filenames, from the command line, drag the files to the executable file in Windows Explorer.

A solution in Visual Studio can contain multiple projects — some .DLL and some .EXE. If a solution contains more than one .EXE project, you must tell Visual Studio which project is the start-up project; the one runs from the Debug menu. To specify a start-up project, right-click that project in Solution Explorer and choose Set As Startup Project. The start-up project’s name appears in boldface in Solution Explorer.

Think of a solution containing two .EXE assemblies as two separate programs that happen to use the same library assemblies. For example, you might have in a solution a console executable and a Windows Forms executable plus some libraries. If you make the console app the start-up project and compile the code, you produce a console app. If you make the Windows Forms app the start-up — well, you get the idea.

Class libraries

A class library contains one or more classes, usually ones that work together in some way. Often, the classes in a library are in their own namespaces. You may build a library of math routines, a library of string-handling routines, and a library of input/output routines, for example.

Sometimes, you even build a whole solution that is nothing but a class library, rather than a program that can be executed on its own. (Typically, while developing this type of library, you also build an accompanying .EXE project to test your library during development. But when you release the library for programmers to use, you release just the .DLL (not the .EXE) — and documentation for it, which you can generate by writing XML comments in the code.)