2.1 Classes, Objects, and Types

The essence of object-oriented programming is the creation of new types. A type represents a thing. Sometimes the thing is abstract, such as a data table or a thread; sometimes it is more tangible, such as a button in a window. A type defines the thing's general properties and behaviors.

If your program uses three instances of a button type in a windowsay, an OK, a Cancel, and a Help buttoneach instance will share certain properties and behaviors. Each, for example, will have a size (though it might differ from that of its companions), a position (though again, it will almost certainly differ in its position from the others), and a text label (e.g., "OK," "Cancel," and "Help"). Likewise, all three buttons will have common behaviors, such as the ability to be drawn, activated, pressed, and so forth. Thus, the details might differ among the individual buttons, but they are all of the same type.

As in many object-oriented programming languages, in C# a type is defined by a class, while the individual instances of that class are known as objects. Later chapters explain that there are other types in C# besides classes, including enums, structs, and delegates, but for now the focus is on classes.

The "Hello World" program declares a single type: the Hello class. To define a C# type, you declare it as a class using the class keyword, give it a namein this case, Helloand then define its properties and behaviors. The property and behavior definitions of a C# class must be enclosed by open and closed braces({}).

C++ programmers take note: There is no semicolon after the closing brace.

2.1.1 Methods

A class has both properties and behaviors. Behaviors are defined with member methods; properties are discussed in Chapter 3.

A method is a function owned by your class. In fact, member methods are sometimes called member functions. The member methods define what your class can do or how it behaves. Typically, methods are given action names, such as WriteLine( ) or AddNumbers( ). In the case shown here, however, the class method has a special name, Main( ), which doesn't describe an action but does designate to the Common Language Runtime (CLR) that this is the main, or first method, for your class.

C++ programmers take note: Main( ) is capitalized in C# and must be a member of a class, not a global member. Main( ) can also return int or void.

The CLR calls Main( ) when your program starts. Main( ) is the entry point for your program, and every C# program must have a Main( ) method.[1]

[1] It is technically possible to have multiple Main( ) methods in C#; in that case you use the /main command-line switch to tell C# which class contains the Main( ) method that should serve as the entry point to the program.

Method declarations are a contract between the creator of the method and the consumer (user) of the method. It is likely that the creator and consumer of the method will be the same programmer, but this does not have to be so: it is possible that one member of a development team will create the method and another programmer will use it.

Java programmers take note: Main( ) is the entry point for every C# program, similar in some ways to the Java run( ) method.

To declare a method, you specify a return value type followed by a name. Method declarations also require parentheses, whether the method accepts parameters or not. For example:

int myMethod(int size);

declares a method named myMethod( ) that takes one parameter: an integer that will be referred to within the method as size. This method returns an integer value. The return value type tells the consumer of the method what kind of data the method will return when it finishes running.

Some methods do not return a value at all; these are said to return void, which is specified by the void keyword. For example:

void myVoidMethod( );

declares a method that returns void and takes no parameters. In C# you must always declare a return type or void.


A C# program can also contain comments. Take a look at the first line after the opening brace:

// Use the system console object

The text begins with two forward slash marks (//). These designate a comment. A comment is a note to the programmer and does not affect how the program runs. C# supports three types of comments.

The first type, just shown, indicates that all text to the right of the comment mark is to be considered a comment, until the end of that line. This is known as a C++ style comment.

C++ programmers take note: C# does not support commenting out sections of code with #if 0...#endif.

The second type of comment, known as a C-style comment, begins with an open comment mark (/*) and ends with a closed comment mark (*/). This allows comments to span more than one line without having to have // characters at the beginning of each comment line, as shown in Example 2-2.

Example 2-2. Illustrating multiline comments
class HelloWorld
    static void Main( )
        /* Use the system console object
           as explained in the text in chapter 2 */
        System.Console.WriteLine("Hello World");

It is possible to nest C++-style comments within C-style comments. For this reason, it is common to use C++-style comments whenever possible, and to reserve the C-style comments for "commenting-out" blocks of code.

The third and final type of comment that C# supports is used to associate external XML-based documentation with your code, and is illustrated in Chapter 13.

2.1.3 Console Applications

"Hello World" is an example of a console program. A console application has no graphical user interface (GUI); there are no list boxes, buttons, windows, and so forth. Text input and output is handled through the standard console (typically a command or DOS window on your PC). Sticking to console applications for now helps simplify the early examples in this book, and keeps the focus on the language itself. In later chapters, we'll turn our attention to Windows and web applications, and at that time we'll focus on the Visual Studio .NET GUI design tools.

All that the Main( ) method does in this simple example is write the text "Hello World" to the monitor. The monitor is managed by an object named Console. This Console object has a method called WriteLine( ) that takes a string (a set of characters) and writes it to the standard output. When you run this program, a command or DOS screen will pop up on your computer monitor and display the words "Hello World."

You invoke a method with the dot operator (.). Thus, to call the Console object's WriteLine( ) method, you write Console.WriteLine(...), filling in the string to be printed.

2.1.4 Namespaces

Console is only one of a tremendous number of useful types that are part of the .NET Framework Class Library (FCL). Each class has a name, and thus the FCL contains thousands of names, such as ArrayList, Hashtable, FileDialog, DataException, EventArgs, and so on. There are hundreds, thousands, even tens of thousands of names.

Java programmers take note: Namespaces provide many of the benefits of packages.

This presents a problem. No developer can possibly memorize all the names that the .NET Framework uses, and sooner or later you are likely to create an object and give it a name that has already been used. What will happen if you develop your own Hashtable class, only to discover that it conflicts with the Hashtable class that .NET provides? Remember, each class in C# must have a unique name.

You certainly could rename your Hashtable class mySpecialHashtable, for example, but that is a losing battle. New Hashtable types are likely to be developed, and distinguishing between their type names and yours would be a nightmare.

The solution to this problem is to create a namespace. A namespace restricts a name's scope, making it meaningful only within the defined namespace.

C++ programmers take note: While in C++ namespaces are delimited with the scope resolution operator (::), in C# you must use the dot (.) operator.

Assume that I tell you that Jim is an engineer. The word "engineer" is used for many things in English, and can cause confusion. Does he design buildings? Write software? Run a train?

In English I might clarify by saying "he's a scientist," or "he's a train engineer." A C# programmer could tell you that Jim is a science.engineer rather than a train.engineer. The namespace (in this case, science or train) restricts the scope of the word that follows. It creates a "space" in which that name is meaningful.

Further, it might happen that Jim is not just any kind of science.engineer. Perhaps Jim graduated from MIT with a degree in software engineering, not civil engineering (are civil engineers especially polite?). Thus, the object that is Jim might be defined more specifically as a science.software.engineer. This classification implies that the namespace software is meaningful within the namespace science, and that engineer in this context is meaningful within the namespace software. If later you learn that Charlotte is a transportation.train.engineer, you will not be confused as to what kind of engineer she is. The two uses of engineer can coexist, each within its own namespace.

Similarly, if it turns out that .NET has a Hashtable class within its System.Collections namespace, and that I have also created a Hashtable class within a ProgCSharp.DataStructures namespace, there is no conflict, because each exists in its own namespace.

In Example 2-1, the Console object's name is restricted to the System namespace by using the code:

System.Console.WriteLine( );

2.1.5 The Dot Operator (.)

In Example 2-1, the dot operator (.) is used both to access a method (and data) in a class (in this case, the method WriteLine( )), and to restrict the class name to a specific namespace (in this case, to locate Console within the System namespace). This works well because in both cases we are "drilling down" to find the exact thing we want. The top level is the System namespace (which contains all the System objects that the Framework provides); the Console type exists within that namespace, and the WriteLine( ) method is a member function of the Console type.

In many cases, namespaces are divided into subspaces. For example, the System namespace contains a number of subnamespaces such as Configuration, Collections, Data, and so forth, while the Collections namespace itself is divided into multiple subnamespaces.

Namespaces can help you organize and compartmentalize your types. When you write a complex C# program, you might want to create your own namespace hierarchy, and there is no limit to how deep this hierarchy can be. The goal of namespaces is to help you divide and conquer the complexity of your object hierarchy.

2.1.6 The using Keyword

Rather than writing the word System before Console, you could specify that you will be using types from the System namespace by writing the statement:

using System;

at the top of the listing, as shown in Example 2-3.

Example 2-3. The using keyword
using System;
class Hello
    static void Main( )
        //Console from the System namespace
        Console.WriteLine("Hello World");

Notice the using System statement is placed before the Hello class definition.

Although you can designate that you are using the System namespace, you cannot designate that you are using the System.Console object, as you can with some languages. Example 2-4 will not compile.

Example 2-4. Code that does not compile (not legal C#)
using System.Console;
class Hello
    static void Main( )
        //Console from the System namespace
        WriteLine("Hello World");

This generates the compile error:

error CS0138: A using namespace directive can only be applied to namespaces; 'System.
Console' is a class not a namespace

The using keyword can save a great deal of typing, but it can undermine the advantages of namespaces by polluting the namespace with many undifferentiated names. A common solution is to use the using keyword with the built-in namespaces and with your own corporate namespaces, but perhaps not with third-party components.

2.1.7 Case Sensitivity

C# is case-sensitive, which means that writeLine is not the same as WriteLine, which in turn is not the same as WRITELINE. Unfortunately, unlike in Visual Basic (VB), the C# development environment will not fix your case mistakes; if you write the same word twice with different cases, you might introduce a tricky-to-find bug into your program.

To prevent such a time-wasting and energy-depleting mistake, you should develop conventions for naming your variables, functions, constants, and so forth. The convention in this book is to name variables with camel notation (e.g., someVariableName), and to name functions, constants, and properties with Pascal notation (e.g., SomeFunction).

The only difference between camel and Pascal notation is that in Pascal notation, names begin with an uppercase letter.

2.1.8 The static Keyword

The Main( )method shown in Example 2-1 has one more designation. Just before the return type declaration void (which, you will remember, indicates that the method does not return a value) you'll find the keyword static:

static void Main( )

The static keyword indicates that you can invoke Main( ) without first creating an object of type Hello. This somewhat complex issue will be considered in much greater detail in subsequent chapters. One of the problems with learning a new computer language is you must use some of the advanced features before you fully understand them. For now, you can treat the declaration of the Main( ) method as tantamount to magic.

    Part I: The C# Language