Your First .NET Framework Application

If the information presented thus far in Chapter 1 seems hopelessly abstract, take heart: things are about to get concrete very quickly. It’s time to develop your first .NET Framework application. And what better way to start than by writing a managed version of “Hello, world”? To keep it simple, we’ll write a console application—one that runs in a command prompt window. That will keep the code as uncluttered as possible and allow us to focus on the issues that matter most.

Hello, World

Figure 1-4 lists the contents of Hello.cs, a C# source code file containing the .NET Framework version of “Hello, world.” To compile it, open a command prompt window, go to the directory where Hello.cs is stored, and type the following command:

csc?/target:exe?/out:Hello.exe?Hello.cs

This command invokes the C# compiler and produces an executable named Hello.exe. The /target switch, which can be abbreviated /t, tells the compiler to produce a console application. Because a console application is the default, and because the default EXE file name is the name of the CS file, you can save wear and tear on your fingers by compiling the program with the command

csc?Hello.cs

Once the compilation process is complete, run Hello.exe by typing hello at the command prompt. “Hello, world” should appear in the window, as shown in Figure 1-5.

Hello.cs
using?System;

class?MyApp
{
????static?void?Main?()
????{
????????Console.WriteLine?("Hello,?world");
????}
}
Figure 1-4
“Hello, world” in C#.
Figure 1-5
Output from Hello.exe.

So what happened when you ran Hello.exe? First, a short x86 stub emitted by the compiler transferred control to the CLR. The CLR, in turn, located and called the program’s Main method, which compiled to three simple CIL instructions. The JIT compiler transformed the instructions into x86 machine code and executed them. Had you compiled and run the EXE on another type of machine, the same CIL instructions would have compiled to instructions native to the host processor.

Inside Hello.cs

Let’s talk about the code in Figure 1-4. For starters, every application has to have an entry point. For a C# application, the entry point is a static method named Main. Every C# application has one. Because C# requires that all methods belong to a type, in Hello.cs, Main is a member of MyApp. There’s nothing magic about the class name; you could name it Foo and it would work just the same. If an application contains multiple classes and multiple Main methods, a /main switch tells the C# compiler which class contains the Main method that’s the entry point.

The one and only statement in MyApp.Main is the one that writes “Hello, world” to the console window. If Hello were a standard Windows application written in C or C++, you’d probably use printf to write the output. But this isn’t a standard Windows application. It’s a .NET Framework application, and .NET Framework applications use the FCL to write to console windows. The FCL’s System namespace features a class named Console that represents console windows. Look up Console in the FCL reference, and you’ll find that it contains a static method named WriteLine that writes a line of text to the window (or to wherever standard output happens to point at the time).

The statement

using?System;

at the beginning of the program is a syntactical simplification. Remember that the FCL contains more than 7,000 members divided into approximately 100 namespaces. Without the using directive, you’d have to qualify the reference to Console by prefacing the class name with the namespace name, as shown here:

System.Console.WriteLine?("Hello,?world");

But with the using directive, you can abbreviate the reference by specifying only the class name. It’s not a big deal here, but when you write programs containing hundreds, perhaps thousands, of references to FCL classes, you’ll appreciate not having to type the namespace names over and over. Most languages support the using directive or an equivalent. In Visual Basic .NET, it’s called Imports.

What happens if two namespaces contain identically named classes and you use both of those classes in your application? Simple: you have to qualify the references one way or another. The following code won’t compile because both namespaces contain classes named ListBox:

using?System.Windows.Forms;
using?System.Web.UI.WebControls;



ListBox?winLB?=?new?ListBox?();?//?Create?a?Windows?Forms?ListBox
ListBox?webLB?=?new?ListBox?();?//?Create?a?Web?Forms?ListBox

Consequently, you have two choices. The first is to fully qualify the class names:

System.Windows.Forms.ListBox?winLB?=new?System.Windows.Forms.ListBox?();
System.Web.UI.WebControls.ListBox?webLB?=
????new?System.Web.UI.WebControls.ListBox?();

The second is to use an alternative form of the using directive to create aliases for the fully qualified class names:

using?winListBox?=?System.Windows.Forms.ListBox;
using?webListBox?=?System.Web.UI.WebControls.ListBox;



winListBox?winLB?=?new?winListBox?();?//?Create?a?Windows?Forms?ListBox
webListBox?webLB?=?new?webListBox?();?//?Create?a?Web?Forms?ListBox

This example is admittedly contrived because you’ll probably never use a Web Forms ListBox and a Windows Forms ListBox in the same program (not for any reason I can think of, anyway). But the principle is valid just the same.

More About the Main Method

Hello’s Main method accepts no parameters and returns no data, but that’s just one of four different ways that you can prototype Main. All of the following are legitimate:

static?void?Main?()
static?int?Main?()
static?void?Main?(string[]?args)
static?int?Main?(string[]?args)

The args parameter is an array of strings containing the program’s command-line arguments. The string at index 0 is the first argument, the string at index 1 is the second, and so on. If you rewrote the program this way:

using?System;

class?MyApp
{
????static?void?Main?(string[]?args)
????{
????????Console.WriteLine?("Hello, " +?args[0]);
????}
}

and started it by typing hello .NET, the output from the program would be “Hello, .NET.” Use the form of Main that receives an args parameter if you want to accept command-line input in your program.

The modified form of Hello.cs in the previous paragraph has one little problem: if you run it without any command-line parameters, it throws an exception because the 0 in args[0] constitutes an invalid array index. To find out how many command-line parameters were entered, read the string array’s Length property, as in:

int?count?=?args.Length;

This statement works because an array in the framework is an instance of System.Array, and System.Array defines a property named Length. You can use Length to determine the number of items in any array, no matter what type of data the array stores.

Inside Hello.exe

If you’d like to see Hello.exe as the CLR sees it, start ILDASM and open Hello.exe. You’ll see the window shown in Figure 1-6. The first red triangle represents the assembly manifest. Double-click it, and you’ll see a list of assemblies that this assembly depends on (“.assembly extern mscorlib”), as shown in Figure 1-7. You’ll also see the assembly name (“.assembly Hello”) and a list of the modules that make up the assembly. Because Hello.exe is a single-file assembly, it’s the only module that appears in the list.

Figure 1-6
ILDASM displaying the contents of Hello.exe.
Figure 1-7
Hello.exe’s manifest.

ILDASM also reveals that Hello.exe contains a class named MyApp and that MyApp contains two methods: a constructor (.ctor) and Main. The constructor was generated automatically by the compiler; it’s a default constructor that takes no arguments. The “S” in the box next to Main indicates that Main is a static method. Double-clicking Main displays the CIL generated for that method by the C# compiler. (See Figure 1-8.) The statement

.entrypoint

isn’t CIL but is simply a directive noting that this method is the program’s entry point. The entry point’s identity came from Hello.exe’s CLR header. Next, the statement

.maxstack?1

is information obtained from the method prologue—data bytes preceding the method in the CIL—indicating that this method requires no more than one slot in the CLR’s evaluation stack. The CLR uses this information to size the evaluation stack prior to invoking the method.

Main’s CIL consists of just three simple instructions:

As you can see, it’s relatively easy to use ILDASM to figure out how a method works. Early .NET Framework developers spent copious amounts of time figuring out how the FCL works by poring over the CIL for individual methods.

Figure 1-8
The Main method disassembled.