Cover | Table of Contents | Colophon
class Hello
{
static void Main(string[] args)
{
// Use the system console object
System.Console.WriteLine("Hello World!");
}
}class keyword, give it a name—in this case, Hello—and then define its properties and behaviors. The property and behavior definitions of a C# class must be enclosed by opening and closing braces ({}).class keyword, give it a name—in this case, Hello—and then define its properties and behaviors. The property and behavior definitions of a C# class must be enclosed by opening and closing braces ({}).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 CLR that this is the main, or first method, for your class.Main( ) when your program starts. Main( ) is the entry point for your program, and every C# program must have a Main( ) method.
HelloWorld), and select a directory in which to store your files. You may also enter the name of the solution containing the project, and select whether you would like Visual Studio 2008 to create a directory for the new solution for you. Click OK, and a new window will appear in which you can enter the code in , as shown in .
+int and bool, and user-defined types (types you create) such as classes, structs, and interfaces. I also cover programming fundamentals, such as how to create and use variables and constants. I'll then introduce enumerations, strings, identifiers, expressions, and statements.if, switch, while, do...while, for, and foreach statements. You'll also learn about operators, including the assignment, logical, relational, and mathematical operators. I'll finish up with a short tutorial on the C# preprocessor.int), and you may create your own types (e.g., Employee).var (covered in ). In this case, C# is able to infer the type of the object and thus, rather than being manifest, is actually implicit.int), and you may create your own types (e.g., Employee).var (covered in ). In this case, C# is able to infer the type of the object and thus, rather than being manifest, is actually implicit.var, at which time it is statically, implicitly, and strongly typed!x and y are variables. You can assign values to your variables, and you can change those values programmatically.using System;
using System.Collections.Generic;
using System.Text;
namespace InitializingVariables
{
class Program
{
static void Main(string[] args)
{
int myInt = 7;
System.Console.WriteLine("Initialized, myInt: {0}",
myInt);
myInt = 5;
System.Console.WriteLine("After assignment, myInt: {0}",
myInt);
}
}
}
Output:
Initialized, myInt: 7
After assignment, myInt: 5using directive for every program. To save space, I've omitted these from most of the code examples after this one.myInt to the value 7, display that value, reassign the variable with the value 5, and display it again.myVariable = 5;
myVariable = 5;
int myVariable = 5; // no problem
int myVariable=5; // no problem
myVariable, the assignment operator (=), and the literal value 5 are "extra." If, however, you were to enter:intMyVariable=5; // error
int and the identifier myVariable is not extra, it is required.Console.WriteLine("Hello World");;). For example:int x; // a statement x = 23; // another statement int y = x; // yet another statement
for, while, do, in, and foreach. I discuss iteration later in this chapter. For now, let's consider some of the more basic methods of conditional and unconditional branching.using System;
namespace CallingAMethod
{
class CallingAMethod
{
static void Main( )
{
Console.WriteLine("In Main! Calling SomeMethod( )...");
SomeMethod( );
Console.WriteLine("Back in Main( ).");
}
static void SomeMethod( )
{
Console.WriteLine("Greetings from SomeMethod!");
}
}
}
Output:
In Main! Calling SomeMethod( )...
Greetings from SomeMethod!
Back in Main( ).Main( ) and proceeds until SomeMethod( ) is invoked (invoking a method is also referred to as "calling" the method). At that point, program flow branches to the method. When the method completes, program flow resumes at the next line after the call to that method.goto, break, continue, return, or throw. I provide additional information about the first three jump statements later in this chapter. The int) support a number of operators such as assignment, increment, and so forth.= symbol causes the operand on the left side of the operator to have its value changed to whatever is on the right side of the operator. Statements that evaluate to a value are called expressions. You may be surprised how many statements do evaluate to a value. For example, an assignment such as:myVariable = 57;
57.57 to the variable myVariable. The assignment operator (=) doesn't test equality; rather, it causes whatever is on the right side (57) to be assigned to whatever is on the left side (myVariable).myVariable = 57 (read aloud as "assign the numeric value 57 to the variable whose name is myVariable") is an expression that evaluates to 57, it can be used as part of another assignment operator, such as:mySecondVariable = myVariable = 57;
57 is assigned to the variable myVariable. The value of that assignment (57) is then assigned to the second variable, mySecondVariable. Thus, the value 57 is assigned to both variables.57 is referred to as a literal value (as opposed to a symbolic value). A symbolic value is one that is housed in a variable, a constant, or an expression. A literal value is the value itself, written in the conventional way.a = b = c = d = e = 20;
+), subtraction (-), multiplication (*), and division (/) operators work as you might expect, with the possible exception of integer division.#). These directives allow you to define identifiers and then test for their existence.#define DEBUG defines a preprocessor identifier, DEBUG. Although other preprocessor directives can come anywhere in your code, identifiers must be defined before any other code, including using statements.DEBUG has been defined with the #if statement. Thus, you can write:#define DEBUG //... some normal code - not affected by preprocessor #if DEBUG // code to include if debugging #else // code to include if not debugging #endif //... some normal code - not affected by preprocessor
#define statement and records the identifier DEBUG. The preprocessor skips over your normal C# code, and then finds the #if - #else - #endif block.#if statement tests for the identifier DEBUG, which does exist, and so the code between #if and #else is compiled into your program—but the code between #else and #endif is not compiled. That code doesn't appear in your assembly at all; it is as though it were left out of your source code.#if statement failed—that is, if you had tested for an identifier that did not exist—the code between #if and #else would not be compiled, but the code between #else and #endif would be compiled.#if/#endif is not affected by the preprocessor and is compiled into your program.#undef. The preprocessor works its way through the code from top to bottom, so the identifier is defined from the int, long, and char. The heart and soul of C#, however, is the ability to create new, complex, programmer-defined types that map cleanly to the objects that make up the problem you are trying to solve.Dog class describes what dogs are like: they have weight, height, eye color, hair color, disposition, and so forth. They also have actions they can take, such as eat, walk, (eat), bark, (eat some more), and sleep. A particular dog (such as Jesse's dog, Milo) has a specific weight (68 pounds), height (22 inches), eye color (black), hair color (yellow), disposition (angelic), and so forth. He is capable of all the actions of any dog (though if you knew him, you might imagine that eating is the only method he implements).Listbox into view, you tell the Listbox control to scroll. How it does so is of no concern to anyone but the person writing the class keyword. The complete syntax is as follows:[attributes] [access-modifiers] class identifier [:[base-class [,interface(s)]] {class-body}
class, which is then followed by the (nonoptional) identifier (the class name).public class Dog : Mammal
{
// class body here
}public is the access modifier, Dog is the identifier, and Mammal is the base class.identifier is the name of the class that you provide. The optional base-class is discussed in . The member definitions that make up the class-body are enclosed by open and closed curly braces ({}).int, char, etc.) are value types, and when they are created as standalone variables (not as part of other objects) they are created on the stack. Objects, however, are reference types and are created on the heap, using the keyword new, as in the following:Time t = new Time( );
t doesn't actually contain the value for the Time object; it contains the address of that (unnamed) object that is created on the heap. t itself is just a reference to that object.Dim and New on the same line, in C#, this penalty doesn't exist. Thus, in C#, there is no drawback to using the new keyword when declaring an object variable.Time object looks as though it is invoking a method:Time t = new Time( );
type.Time class of doesn't define a constructor. Because a constructor is not declared, the compiler provides one for you. The default constructor creates the object but takes no other action.Type | Default value |
|---|---|
numeric (int, long, etc.) | 0 |
bool | false |
char | '\0' (null) |
enum | 0 |
Reference types | null |
Button and have instantiated two objects of that class named btnUpdate and btnDelete. Suppose as well that the Button class has a static method SomeMethod( ). To access the static method, you write:Button.SomeMethod( );
btnUpdate.SomeMethod( );
static keyword in C# with the Static keyword in VB 6 and VB.NET. In VB, the Static keyword declares a variable that is available only to the method in which it was declared. In other words, the Static variable is not shared among different objects of its class (i.e., each Static variable instance has its own value). However, this variable exists for the life of the program, which allows its value to persist from one method call to another.static keyword indicates a class member. In VB, the equivalent keyword is Shared.IDisposable interface. (You will learn more about interfaces in .) The IDisposable interface requires its implementers to define one method, named Dispose( ), to perform whatever cleanup you consider to be crucial. The availability of Dispose( ) is a way for your clients to say, "Don't wait for the finalizer to be called, do it right now."Dispose( ) method, you should stop the garbage collector from calling your object's finalizer. To do so, call the static method GC.SuppressFinalize( ), passing in the this pointer for your object. Your finalizer can then call your ref parameter modifier for passing value objects into a method by reference, and the out modifier for those cases in which you want to pass in a variable by reference without first initializing it.params modifier, which allows a method to accept a variable number of parameters. We discuss the params keyword in .Time class and add a GetTime( ) method, which returns the hour, minutes, and seconds.using System;
namespace ReturningValuesInParams
{
public class Time
{
// private member variables
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second;
// public accessor methods
public void DisplayCurrentTime( )
{
System.Console.WriteLine( "{0}/{1}/{2} {3}:{4}:{5}",
Month, Date, Year, Hour, Minute, Second );
}
public int GetHour( )
{
return Hour;
}
public void GetTime( int h, int m, int s )
{
h = Hour;
m = Minute;
s = Second;
}
// constructor
public Time( System.DateTime dt )
{
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
}
public class Tester
{
static void Main( )
{
System.DateTime currentTime = System.DateTime.Now;
Time t = new Time( currentTime );
t.DisplayCurrentTime( );
int theHour = 0;
int theMinute = 0;
int theSecond = 0;
t.GetTime( theHour, theMinute, theSecond );
System.Console.WriteLine( "Current time: {0}:{1}:{2}",
theHour, theMinute, theSecond );
}
}
}
Output:
11/17/2007 13:41:18
Current time: 0:0:0DateTime object. It would be convenient to be able to set new Time objects to an arbitrary time by passing in year, month, date, hour, minute, and second values. It would be even more convenient if some clients could use one constructor, and other clients could use the other constructor. Function overloading provides for these exact contingencies.void myMethod(int p1); void myMethod(int p1, int p2); void myMethod(int p1, string s1);
void myMethod(int p1); string myMethod(int p1, int p2); // legal void otherMethod(int p1); string otherMethod(int p1); // not legal
myMethod is overloaded by changing the number of parameters, and the two versions may have different return types. On the other hand, the signature of otherMethod is unchanged in the two versions, and changing the return type is not enough to overload the method.Time class with two constructors: one that takes a DateTime object, and the other that takes six integers.using System;
namespace OverloadedConstructor
{
public class Time
{
// private member variables
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second;
// public accessor methods
public void DisplayCurrentTime( )
{
Console.WriteLine( "{0}/{1}/{2} {3}:{4}:{5}",
Month, Date, Year, Hour, Minute, Second );
}
// constructors
public Time( System.DateTime dt )
{
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
public Time( int Year, int Month, int Date,
int Hour, int Minute, int Second )
{
this.Year = Year;
this.Month = Month;
this.Date = Date;
this.Hour = Hour;
this.Minute = Minute;
this.Second = Second;
}
}
public class Tester
{
static void Main( )
{
DateTime currentTime = DateTime.Now;
Time t1= new Time( currentTime );
t.DisplayCurrentTime( );
Time t2 = new Time( 2007, 11, 18, 11, 03, 30 );
t2.DisplayCurrentTime( );
}
}
}
Output:
11/20/2007 17:7:54
11/18/2007 11:3:30Time class is first created, the Hour value might be stored as a member variable. When the class is redesigned, the Hour value might be computed or retrieved from a database. If the client had direct access to the original Hour member variable, the change to computing the value would break the client. By decoupling and forcing the client to go through a method (or property), the Time class can change how it manages its internal state without breaking client code.