Cover | Table of Contents | Colophon
System.Object.
The CTS supports the general concept of classes, interfaces,
delegates (which support callbacks), reference types, and value
types.
class HelloWorld
{
static void Main( )
{
// Use the system console object
System.Console.WriteLine("Hello World");
}
}
HelloWorld displays the
words "Hello World" at the console. Let's take a
closer look at this simple program.
HelloWorld class. To define a C# type, you declare
it as a class using the
class
keyword, give it a
name—in this case, HelloWorld—and then
define its properties and behaviors. The property and behavior
definitions of a C# class must be enclosed by open and closed braces
({}
).
File
→
New
→
Project from the menu toolbar. This will invoke
the New Project window (if you are using Visual Studio for the first
time, the New Project window might appear without further prompting).
Figure 2-1 shows the New Project window.
Debug->Start
or just press F5. The program will compile and run to the
breakpoint, at which time it will stop
and a yellow arrow will indicate the next statement for execution, as
in Figure 2-6.
int,
bool, etc.) versus user-defined types (types you
create as classes and interfaces). The chapter also covers
programming fundamentals such as how to create and use variables and
constants. It then goes on to introduce enumerations, strings,
identifiers, expressions, and statements.
if,
switch, while,
do...while, for, and
foreach statements. Also discussed are operators,
including the assignment, logical, relational, and mathematical
operators. This is followed by an introduction to namespaces and a
short tutorial on the C# precompiler.
int
indicates an object of 4 bytes) and its capabilities (e.g., buttons
can be drawn, pressed, and so forth).
int
indicates an object of 4 bytes) and its capabilities (e.g., buttons
can be drawn, pressed, and so forth).
class Values
{
static void Main( )
{
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: 5
myInt to the value
7, display that value, reassign the variable with
the value 5, and display it again.
myVariable = 57;
57.
57 to the variable myVariable.
The assignment operator
(=) does not test equality; rather it causes
whatever is on the right side (57) to be assigned
to whatever is on the left side (myVariable). All
of the C# operators (including assignment and equality) are discussed
later in this chapter (see Section 3.6).
myVariable = 57 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. You can thus
initialize any number of variables to the same value with one
statement:
a = b = c = d = e = 20;
myVariable = 5;
myVariable = 5;
Console.WriteLine("Hello World")
int x = 5;
int x=5;
intx=5;
int and the variable name
x is not extra, and is
required. This is not surprising; the whitespace allows the compiler
to parse the keyword int rather than some unknown
term intx. You are free to add as much or as
little whitespace between int and
x as you care to, but there must be at least one
whitespace character (typically a space or tab).
;). For
example:
int x; // a statement x = 23; // another statement int y = x; // yet another statement
for
,
while, do,
in, and
foreach
. Iteration is discussed later in
this chapter. For now, let's consider some of the more basic
methods of conditional and unconditional branching.
using System;
class Functions
{
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
sometimes 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.
int) support a number of operators such as
assignment, increment, and so forth. Their use is highly intuitive,
with the possible exception of the assignment operator
(=) and the equality operator
(==), which are often confused.
+),
subtraction (-),
multiplication (*),
and
division
(/) operators work as you might expect, with the
possible exception of integer division.
17/4 = 4, with a
remainder of 1). C# provides a special
operator,
modulus (%),
described in the next section, to retrieve the remainder.
%). For example, the statement
17%4 returns 1 (the remainder
after integer division).
namespace keyword, followed by the name you wish
to create. Enclose the objects for that namespace within braces, as
illustrated in Example 3-19.
namespace Programming_C_Sharp
{
using System;
public class Tester
{
public static int Main( )
{
for (int i=0;i<10;i++)
{
Console.WriteLine("i: {0}",i);
}
return 0;
}
}
}
Programming_C_Sharp, and also specifies a
Tester class which lives within that namespace.
You can alternatively choose to nest your namespaces, as needed, by
declaring one within another. You might do so to segment your code,
creating objects within a nested namespace whose names are protected
from the outer namespace, as illustrated in Example 3-20.
namespace Programming_C_Sharp
{
namespace Programming_C_Sharp_Test
{
using System;
public class Tester
{
public static int Main( )
{
for (int i=0;i<10;i++)
{
Console.WriteLine("i: {0}",i);
}
return 0;
}
}
}
}
Tester object now declared within the
Programming_C_Sharp_Test namespace is:
Programming_C_Sharp.Programming_C_Sharp_Test.Tester
Tester
object in any other namespace, including the outer namespace
Programming_C_Sharp.
#).
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 does not appear in your
assembly at all; it is as if it were left out of your source code.
#if statement failed—that is, if you
had tested for an identifier which did not exist—the code
between #if and #else would not
be compiled, but the code between #else and
#endif would be compiled.
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, bark,
and sleep. A particular dog (such as my dog Milo) will have a
specific weight (62 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).
class
keyword. The complete syntax is as follows:
[ attributes] [access-modifiers ] class identifier [:base-class] { class-body }
public
as an access modifier.) The
identifier is the name of the class that you provide. The
optional base-class is discussed in Chapter 5. The member definitions that make up the
class-body are enclosed by open and closed
curly
braces ({}).
Tester:
public class Tester
{
public static int Main( )
{
/...
}
}
Tester objects. What is the difference between a
class and an instance of that class? To answer that question, start
with the distinction between the type
int
and a
variable
of type int. Thus, while you would write:
int myInteger = 5;
int = 5;
int).
int, char, etc.) are value
types, and 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 does not 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.
Time object looks as though it is invoking a
method:
Time t = new Time( );
type.
Time class of Example 4-1
does not define a constructor. If a constructor is not declared, the
compiler provides one for you. The default constructor creates the
object but takes no other action. Member variables are initialized to
innocuous values (integers to 0, strings to the empty string, etc.).
Table 4-2 lists the default values assigned to
primitive types.
|
Type
|
Default Value
|
|---|---|
|
|
Button and have
instantiated 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( );
Main( )
method
is static. Static methods are said to operate on the class, rather
than on an instance of the class. They do not have a
this reference, as there is no instance to point
to.
Finalize(
)
method (called a
finalizer), which will be called by the
garbage collector when your object
is destroyed.
Finalize() method; you want this only for
handling unmanaged resources. Because there is some cost to having a
finalizer, you ought to implement this only on methods that require
it (that is, methods that consume valuable unmanaged resources).
Finalize( )
method directly (except that you can call the base class'
Finalize( ) method in your own Finalize(
)). The garbage collector will call Finalize(
) for you.
~MyClass( ){}
Finalize( ) method that chains up to its base
class. Thus, writing:
~MyClass( )
{
// do work here
}
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 ref variable without first initializing
it. C# also supports the params modifier which
allows a method to accept a variable number of parameters. The
params keyword is discussed in Chapter 9.
Time class and add a GetTime( )
method which returns the hour, minutes, and seconds.
public class Time
{
// 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;
}
// private member variables
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int 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);
}
}
DateTime 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 exactly these contingencies.
void myMethod(int p1); void myMethod(int p1, int p2); void myMethod(int p1, string s1);
Time
class with two constructors, one which takes a
DateTime object, and the other which takes six
integers.
public class Time
{
// public accessor methods
public void DisplayCurrentTime( )
{
System.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;
}
// private member variables
private int Year;
private int Month;
private int Date;
private int Hour;
private int Minute;
private int Second;
}
public class Tester
{
static void Main( )
{
System.DateTime currentTime = System.DateTime.Now;
Time t = new Time(currentTime);
t.DisplayCurrentTime( );
Time 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.
public class Time
{
// public accessor methods
public void DisplayCurrentTime( )
{
System.Console.WriteLine(
"Time\t: {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;
}
// create a property
public int Hour
{
get
{
return hour;
}
set
{
hour = value;
}
}Time class
that is responsible for providing public static values representing
the current time and date. Example 4-12 illustrates a
simple approach to this problem.
public class RightNow
{
static RightNow( )
{
System.DateTime dt = System.DateTime.Now;
Year = dt.Year;
Month = dt.Month;
Date = dt.Day;
Hour = dt.Hour;
Minute = dt.Minute;
Second = dt.Second;
}
// private member variables
public static int Year;
public static int Month;
public static int Date;
public static int H