Flylib.com

Books Software

 
 
 

Sample C Program


Sample C# Program

In deference to Martin Richards, the founder of the BCPL language and author of the first "Hello, World!" program, I present a "Hello, World!" program. Actually, I offer an enhanced version that displays "Hello, World" in English, Italian, or Spanish. The program is a console application. For simplicity, no error checking is performed. C# is case sensitive.

Here is my version of the HelloWorld program:

using System; namespace HelloNamespace { class Greetings{ public static void DisplayEnglish() { Console.WriteLine("Hello, world!"); } public static void DisplayItalian() { Console.WriteLine("Ciao, mondo!"); } public static void DisplaySpanish() { Console.WriteLine("Hola, imundo!"); } } delegate void delGreeting(); class HelloWorld { static void Main(string [] args) { int iChoice=int.Parse(args[0]); delGreeting [] arrayofGreetings={ new delGreeting(Greetings.DisplayEnglish), new delGreeting(Greetings.DisplayItalian), new delGreeting(Greetings.DisplaySpanish)}; arrayofGreetings[iChoice-1](); } } }

Csc.exe is the C# compiler. The following csc command compiles the hello.cs source file to create the executable hello.exe, which is a .NET assembly:

csc hello.cs

As a .NET assembly, the Hello.exe contains metadata and MISL code but not native binary.

Run the Hello application from the command line. Enter the program name and the language (1 for English, 2 for Italian, or 3 for Spanish). For example, the following command line displays "Ciao, mondo" ("Hello, world" in Italian).

Hello 2

The source code of the Hello application has the features common to most .NET applications: a using statement, a namespace, types, access modifiers, methods , and data.

{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}

The HelloNamespace namespace contains the Greetings and HelloWorld types. The Greetings class has three static methods, and each method displays "Hello, World" in a different language. Static methods are invoked on the type ( classname . member ), not an instance of that type. The static methods of the Greetings type are also public and therefore visible inside and outside the class.

Delegates define a type of function pointer. The delGreeting delegate is a container for functions pointers that point to functions that return void and have no parameters. This is not so coincidentally the function signature of the methods in the Greetings type.

The entry point of this and any other C# application is the Main method. Command-line parameters are passed as the args parameter, which is a string array. In the Hello program, the first element of the args array is a number indicating the language of choice, as inputted by the user . The Hello application converts that element to an integer. Next , the program defines an array of function pointers, which is initialized with function pointers to methods of the Greetings class. This statement invokes a function pointer to display the chosen Hello message:

arrayofGreetings[iChoice-1]()

The variable iChoice is an index into the delegate array. It is decremented to account for the fact that arrays in C# are zero-based .

The remainder of the chapter discusses the important features of the Hello and any other C# application, except for types that will be reviewed in the next chapter.



Namespaces

Namespaces provide hierarchical clarity and organization of types and other members. A container of hundreds of classes, the .NET Framework Class Library (FCL) is an example of effective use of namespaces. The Framework Class Library would sacrifice clarity if planned as a single namespace with a flat hierarchy. Instead, the Framework Class Library organizes its members into numerous namespaces. System , which is the root namespace of the FCL, contains the classes ubiquitous to .NET, such as the Console class. Types related to data services are grouped in the System.Data namespace. Data services are further delineated in the System.Data.SqlClient namespace, which contains types specific to Microsoft SQL. The remaining types are organized similarly in other namespaces.

A namespace identifier must be unique within the namespace declaration space, which contains the current namespace but not a nested namespace. A nested namespace is considered a member of the containing namespace. Use the dot punctuator (.) to access members of the namespace.

A namespace at file scope, not nested within another namespace, is considered part of the compilation unit and included in the global namespace. A compilation unit is a source code file. A program partitioned into several source files has multiple compilation units—one compilation unit for each source file. Any namespace, including the global namespace, can span multiple compilation units. For example, all types defined at file scope are included into a single global namespace that spans separate source files.

The following code has two compilation units and three namespaces. Because of identical identifiers sharing the same scope, errors occur when the program is compiled.

// file1.cs public class ClassA { } public class ClassB { } namespace NamespaceZ { public class ClassC { } } // file2.cs public class ClassB { } namespace NamespaceY { public class ClassA { } } namespace NamespaceZ { public class ClassC { } public class ClassD { } }

Compile the code into a library:

csc /t:library file1.cs file2.cs

In the preceding code, the global namespace has four members. NamespaceY and NamespaceZ are members. The classes ClassA and ClassB are also members of the global namespaces. The members span the File1.cs and File2.cs compilation units, which both contribute to the global namespace.

ClassB and ClassC are ambiguous. ClassB is ambiguous because it is defined twice in the global namespace, once in each compilation unit. ClassC is defined in the NamespaceZ namespace in both compilation units. Because NamespaceZ is one cohesive namespace, ClassC is also ambiguous.

The relationship between compilation units, the global namespace, and nonglobal namespaces are illustrated in the Figure 1-3.

image from book
Figure 1-3: Global vs. non-global namespaces

{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}

The using directive makes a namespace implicit. You can access members of the named namespace directly without the fully qualified name . Do you refer to members of your family by their fully qualified names or just their first names? Unless your mother is the queen , you probably refer to everyone directly by simply using their first names , for the sake of convenience. The using directive means that you can treat members of a namespace like family members.

The using directive must precede any members in the namespace where it is defined. The following code defines the namespace member ClassA . The fully qualified name is NamespaceZ.NamespaceY.ClassA . Imagine having to type that several times in a program!

using System; namespace NamespaceZ { namespace NamespaceY { class ClassA { public static void FunctionM() { Console.WriteLine("FunctionM"); } } } } namespace Application { class Starter { public static void Main() { NamespaceZ.NamespaceY.ClassA.FunctionM(); } } }

The following using directive makes NamespaceZ.NamespaceY implicit. Now you can directly access ClassA .

namespace Application { using NamespaceZ.NamespaceY; class Starter { public static void Main() { ClassA.FunctionM(); } } }

Ambiguities can occur when separate namespaces with identically named members are made implicit. When this occurs, the affected members can be assessed only with their fully qualified names.

The using directive can also define an alias for a namespace or type. Aliases are typically created to resolve ambiguity or as a convenience. The scope of the alias is the declaration space where it is declared. The alias must be unique within that declaration space. In this source code, an alias is created for the fully qualified name of ClassA :

namespace Application { using A=NamespaceZ.NamespaceY.ClassA; class Starter { public static void Main() { A.FunctionM(); } } }

In this code, A is a nickname for NamespaceZ.NamespaceY.ClassA and can be used synonymously.

Using directive statements are not cumulative and are evaluated independently.