Professional Documents
Culture Documents
0
Application Design
FunctionX Press
INDEX
1 - INTRODUCTION TO C#...............................................................................................................................14
INTRODUCTION...................................................................................................................................................14
C# is a Sharp C.............................................................................................................................................14
Console Applications....................................................................................................................................14
WRITING CODE...................................................................................................................................................16
Practical Learning: Creating a Program.....................................................................................................16
Comments......................................................................................................................................................16
Practical Learning: Creating Comments......................................................................................................16
Code Colors..................................................................................................................................................17
Indentation....................................................................................................................................................18
SOLUTION AND PROJECT MANAGEMENT............................................................................................................18
A Project........................................................................................................................................................18
Saving a Project............................................................................................................................................19
A Solution......................................................................................................................................................19
Executing a Project.......................................................................................................................................21
Practical Learning: Executing an Application.............................................................................................22
Adding a Project...........................................................................................................................................22
2 - INTRODUCTION TO VARIABLES............................................................................................................25
VARIABLES.........................................................................................................................................................25
Practical Learning: Introducing Variables..................................................................................................25
Names in C#..................................................................................................................................................25
Values and Variables on the Console...........................................................................................................27
THE NUMERIC SYSTEMS.....................................................................................................................................27
The Binary System.........................................................................................................................................28
The Decimal System......................................................................................................................................28
The Hexadecimal System...............................................................................................................................29
Signed and Unsigned.....................................................................................................................................30
Data Types....................................................................................................................................................30
REPRESENTING NUMBERS...................................................................................................................................31
A Bit...............................................................................................................................................................32
The Four-Bit Combination............................................................................................................................32
A BYTE...............................................................................................................................................................35
Characters.....................................................................................................................................................36
Escape Sequences..........................................................................................................................................37
The Byte Data Type.......................................................................................................................................38
Practical Learning: Using Bytes...................................................................................................................39
Signed Byte....................................................................................................................................................40
A WORD..............................................................................................................................................................41
Short Integers................................................................................................................................................42
Unsigned Short Integers................................................................................................................................43
Practical Learning: Using Unsigned Short Integers....................................................................................44
3 – USING VARIABLES......................................................................................................................................46
A DOUBLE-WORD...............................................................................................................................................46
Practical Learning: Using Unsigned Integers..............................................................................................48
Signed Integers..............................................................................................................................................49
Unsigned Integers.........................................................................................................................................50
Practical Learning: Using Unsigned Integers..............................................................................................51
A QUAD-WORD..................................................................................................................................................52
Long Integers................................................................................................................................................53
Unsigned Long Integers................................................................................................................................55
REAL NUMBERS..................................................................................................................................................55
Floating-Point Numbers................................................................................................................................56
Double-Precision Numbers...........................................................................................................................56
Practical Learning: Using a Double-Precision Variable.............................................................................58
Decimal.........................................................................................................................................................59
Practical Learning: Using Decimal Values..................................................................................................62
ACCESSORY DATA TYPES...................................................................................................................................63
Strings...........................................................................................................................................................63
Introduction
C# is a Sharp C
C#, pronounced c sharp, is a computer language used to give instructions that tell the
computer what to do, how to do it, and when to do it. This is a universal language that is
used on many operating systems, including Microsoft Windows. C# is one of the
languages used in the Microsoft .NET Framework. The Microsoft .NET Framework is a
library of objects that create or draw things on the computer.
Console Applications
The C# language is used to create applications that display on a black window referred to
as the DOS prompt or DOS window. Those are the types of applications we will create in
our lessons.
To study the C# language, we will use Microsoft Visual C# 2008 Express Edition or
Microsoft Visual C# 2008 Professional. To get Microsoft Visual C# 2008 Express Edition,
you can download it free from the Microsoft web site. After downloading it, you can
install it.
To launch Microsoft Visual C# 2008 Express Edition, you can click Start -> (All) Programs
-> Microsoft Visual C# 2008 Expression Edition:
To launch Microsoft Visual C# 2008 Professional, you can click Start -> (All) Programs ->
Microsoft Visual Studio 2008. To create the type of applications we will study in our
lessons, on the main menu, you can click File -> New Project... In the Templates section
of the New Project dialog box, you can click Console Application, accept the default name
or change it:
After clicking OK, a skeleton code would be created for you. Right now, we will not review
every part of the code. Everything will be introduced and explained as we move on.
Introduction
The programs we will write are meant to give instructions to the computer about what to
do, when to do something, and how to do it. You write these instructions in an easy to
understand English format, using words we will study. This means that a regular
instruction uses normal text with alphabetic characters, numbers, and non-readable
symbols. Normally, you can write your instructions using any text editor such as Notepad,
WordPad, WordPerfect, or Microsoft Word, etc. When writing your instructions, there are
rules your must follow and suggestions you should observe. We sill study each one of
them as we move on.
The group of instructions used by your program is also referred to as code. To assist you
with writing code, Microsoft Visual C# 2008 includes a text editor referred to as the Code
Editor. This is the window that displays when you have just created a console application.
Besides the Code Editor, the integrated development interface (IDE) of the Microsoft
Visual C# 2008 is made of various parts, which we will review when necessary.
2. To create a new application, on the Start Page, on the right side of Create, click
Project
Comments
A comment is a line or paragraph of text that will not be considered as part of your code
of a program. There are two types of comments recognized by C#.
To display a comment on a line of text, start the line with two forward slashes //. Anything
on the right side of // would be ignored. Here is an example:
// This line will be ignored. I can write in it anything I want
The above type of comment is used on only one line. You can also start a comment
with /*. This type of comment ends with */. Anything between this combination of /* and
*/ would not be read. Therefore, you can use this technique to span a comment on more
than one line.
2. To save the project, on the Standard toolbar, click the Save All button
Code Colors
Code is written in a wide area with a white background. This is the area you use the
keyboard to insert code with common readable characters. The Code Editor uses some
colors to differentiate categories of words or lines of text. The colors used are highly
customizable. To change the colors, on the main menu, you can click Tools -> Options...
In the Options dialog box, in the Environment section, click Fonts and Colors. To set the
color of a category, in the Display Items section, click the category. In the Item
Foreground combo box, select the desired color. If you want the words of the category to
have a colored background, click the arrow of the Item Background combo box and select
one:
Indentation
Indentation is another feature that makes your program easy to read. Indentation is a
technique of grouping lines of code by category. To delimit the items of your code, you
should indent them by two empty spaces or one tab. Indentation should be incremental.
That is, when a line of code appears to be a child of the previous line, the new line should
be indented.
A Project
We have seen how to create a console application. Microsoft Visual C# allows you to
create various other types of applications. This is why you should first display the New
Project dialog box to select your option. Besides console applications, in future lessons, we
will start some applications with the Empty Project. We will also learn how to create a
library using the Class Library option. We will ignore the other three options in this book.
To control the indentation of your code, on the main menu, click Tools -> Options... In the
left list, expand C#, followed by Formatting and click Indentation. Then change the
options on the right side:
Saving a Project
In previous versions of Microsoft Visual C# (namely 2002 and 2003), you always had to
formally create a project in order to use one and you always had to save it. After realizing
that many of the projects that developers or students create are for experimental
purposes, Microsoft provided the ability to only temporarily create a project, then to save
it or not. Saving a project allows you to keep on a medium so you can refer to it later.
When Microsoft Visual Studio 2008 (any edition) is installed, it creates a folder named
Visual Studio 2008 in your My Documents folder. The My Documents folder is called your
personal drive or your personal directory. Inside of the Visual Studio 2008 folder, it creates
a sub-folder named Projects. By default, this is where it would save your projects, each
with its own folder.
To save a project, on the Standard toolbar, you can click the Save All button .
Alternatively, on the main menu, you can click File -> Save All. If the project had already
been saved but you want to save it under a different name, on the main menu, you can
click File -> Save project name As...
A Solution
When creating a project, the solution holds the same name as the project. You can see
their names in the Solution Explorer:
C# 3.0 Practical Learning 18
The solution and a project can have different names. While working on a project, to
rename the solution, in the Solution Explorer, you can click the first node, which is the
name of the solution starting with Solution. Then, in the Properties window, click (Name)
and type the name of your choice:
This name is temporary, especially if you have not yet saved the project. If you want to
permanently save a solution for later use, there are two techniques you can use.
If you start saving a project for the first time, it would bring the Save Project dialog box.
By default, Microsoft Visual Studio selects your personal directory as the path to the
solution. This is called the location. In the location, Microsoft Visual Studio creates a folder
as the solution of the project. The solution must have, or must be stored, in its own
folder. As mentioned earlier, Microsoft Visual Studio uses the name of the project as the
name of the solution. To rename the solution, you can change the string in the Solution
Name text box. Remember that you can enter the name of the project in the Name text
box. Here is an example:
If the project had already been saved but you want to change the name of the solution,
on the main menu, you can click File -> Save solution-name.sln As... This would bring the
Save File As dialog box where you can specify the name of the solution and click Save.
Executing a Project
After creating a project and writing code, you may want to see the result. To do this, you
must execute the application. This would create an executable that you can use on other
computers and that you can distribute to other people.
To execute an application, on the main menu, you can click Debug -> Start Without
Debugging. Instead of going through the main menu every time, you can add the Start
Without Debugging button to a toolbar. To do this, you can right-click any toolbar and
click Customize... In the Commands property page of the Customize dialog box, you can
click Debug in the Categories click, then drag Start Without Debugging, and drop it on a
toolbar. Here is an example:
1. To execute the application, on the main menu, click Debug -> Start Without
Debugging
Adding a Project
One of the most valuable features of Microsoft Visual Studio 2005 is that it allows you to
work on more than one project without launching more than one instance of the studio.
This means that you can add a project to another project you are working on and treat
each as a separate entity.
If you have a project that was previously saved but you don't want to open a separate
instance of Microsoft Visual Studio for it, you can click Existing Project... This would bring
the Add Existing Project dialog box that allows you to select a project from a folder.
To add a new project, after right-clicking, you can click New Project... If you add a new
project, and if you want to keep it for future references, you must save it. To save the
new project, you can click the Save All button on the Standard toolbar. After saving the
new project, a folder with its name would be created inside of the folder of the solution.
On the right side of the name of the solution in Solution, the number of its projects is
specified in parentheses, as 1 project, or 2 projects, etc.
After adding a project, each would be represented by its own node in the Solution
Explorer and in the Class View. Here is an example:
Also, a sub-folder for each project is created in the folder of the solution:
Variables
Definition
Data used by the computer comes and goes regularly as this information changes. For this
reason, such information is called a variable.
When the user enters data in a program, the computer receives it and must store it
somewhere to eventually make it available to the program as needed. For a program used
to process employment applications, the types of information a user would enter into the
program are the name, the residence, the desired salary, years of experience, education
level, etc. Because there can be so much information for the same program, you must
specify to the computer what information you are referring to and when. To do this, each
category of piece of information must have a name.
2. To create a new application, on the Start Page, on the right side of Create, click
Project
Names in C#
Besides these keywords, C# has other words that should be reserved only depending on how
and where they are used. These are referred to as contextual keywords and they are:
Once you avoid these words, there are rules you must follow when naming your objects.
On this site, here are the rules we will follow:
After the first letter or underscore, the name can have letters, digits, and/or
underscores
The name must not have any special characters other than the underscore
Besides these rules, you can also create your own but that abide by the above.
C# 3.0 Practical Learning 25
C# is case-sensitive. This means that the names Case, case, and CASE are completely
different. For example, main is always written Main.
As mentioned already, the applications we will create display in a dark object called the
DOS window. Here is an example showing some values:
To display a value in this window, you can enter it in the parentheses of the
Console.Write() or Console.WriteLine(). Here are two examples:
using System;
class Program
{
static void Main()
{
Console.WriteLine(248);
Console.Write(1);
}
}
Introduction
When a computer boots, it “loads” the operating system. If you want to use a program,
you must find it either on the Start menu or from its directory and take the necessary
action to open it. Such a program uses numbers, characters, meaningful words, pictures,
graphics, etc, that are part of the program. As these things are numerous, so is the size of
the program, and so is the length of time needed to come up. Your job as a programmer
is to create such programs and make them available to the computer, then to people who
want to interact with the machine.
Some of the instructions you will give to the computer could consist of counting the
number of oranges, converting water to soup, or making sure that a date occurs after
January 15. After typing an instruction, the compiler would translate it to machine
language. The computer represents any of your instructions as a group of numbers. Even
if you ask the computer to use an orange, it would translate it into a set of numbers. As
you give more instructions or create more words, the computer stores them in its memory
using a certain amount of space for each instruction or each item you use.
There are three numeric systems that will be involved in your programs, with or without
your intervention.
When dealing with assignments, the computer considers a piece of information to be true
or to be false. To evaluate such a piece, it uses two symbols: 0 and 1. When a piece of
information is true, the computer gives it a value of 1; otherwise, its value is 0. Therefore,
the system that the computer recognizes and uses is made of two symbols: 0 and 1. As
the information in your computer is greater than a simple piece, the computer combines
0s and 1s to produce all sorts of numbers. Examples of such numbers are 1, 100, 1011, or
1101111011. Therefore, because this technique uses only two symbols, it is called the
binary system.
When reading a binary number such as 1101, you should not pronounce "One Thousand
One Hundred And 1", because such a reading is not accurate. Instead, you should
pronounce 1 as One and 0 as zero or o. 1101 should be pronounced One One Zero One,
or One One o One.
The sequence of the symbols of the binary system depends on the number that needs to
be represented.
The numeric system that we are familiar with uses ten symbols that are 0, 1, 2, 3, 4, 5, 6,
7, 8, and 9. Each of these symbols is called a digit. Using a combination of these digits,
you can display numeric values of any kind, such as 240, 3826 or 234523. This system of
representing numeric values is called the decimal system because it is based on 10 digits.
The decimal system is said to use a base 10. This allows you to recognize and be able to
read any number. The system works in increments of 0, 10, 100, 1000, 10000, and up. In
the decimal system, 0 is 0*10 0 (= 0*1, which is 0); 1 is 1*10 0 (=1*1, which is 1); 2 is
2*100 (=2*1, which is 2), and 9 is 9*10 0 (= 9*1, which is 9). Between 10 and 99, a
number is represented by left-digit * 101 + right-digit * 100. For example, 32 = 3*101 +
2*100 = 3*10 + 2*1 = 30 + 2 = 32. In the same way, 85 = 8*10 1 + 5*100 = 8*10 + 5*1
= 80 + 5 = 85. Using the same logic, you can get any number in the decimal system.
Examples are:
2751 = 2*103 + 7*102 + 5*101 + 1*100 = 2*1000 + 7*100 + 5*10 + 1 = 2000 + 700 +
50 + 1 = 2751
etc Add 0 to the preceding value 1000000 100000 10000 1000 100 10 0
When these numbers get large, they become difficult to read; an example is
279174394327. To make this easier to read, you can separate each thousand fraction with
a comma. Our number would become 279,174,394,327. You can do this only on paper,
never in a program: the compiler would not understand the comma(s).
While the decimal system uses 10 digits (they are all numeric), the hexadecimal system
uses sixteen (16) symbols to represent a number. Since the family of Latin languages
consists of only 10 digits, we cannot make up new ones. To compensate for this, the
hexadecimal system uses alphabetic characters. After counting from 0 to 9, the system
uses letters until it gets 16 different values. The letters used are a, b, c, d, e, and f, or
their uppercase equivalents A, B, C, D, E, and F. The hexadecimal system counts as
follows: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f; or 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C,
D, E, F. To produce a hexadecimal number, you use a combination of these sixteen
symbols.
Examples of hexadecimal numbers are 293, 0, df, a37, c23b34, or ffed54. At first glance, the
decimal representation of 8024 and the hexadecimal representation of 8024 are the same.
Also, when you see fed, is it a name of a federal agency or a hexadecimal number? Does CAB
represent a taxi, a social organization, or a hexadecimal number?
From now on, to express the difference between a decimal number and a
hexadecimal one, each hexadecimal number will start with 0x or 0X. The number
will be followed by a valid hexadecimal combination. The letter can be in
uppercase or lowercase.
The numbers we have used so far were counting from 0, then 1, then 2, and up to any
number desired, in incrementing values. Such a number that increments from 0, 1, 2, and
up is qualified as positive. By convention, you do not need to let the computer or someone
else know that such a number is positive: by just displaying or saying it, the number is
considered positive. This is the basis of our counting items.
In real life, there are numbers counted in decrement values. Such numbers start at –1 and
move down to -2, -3, -4 etc. These numbers are qualified as negative.
When you write a number “normally”, such as 42, 502, or 1250, the number is positive. If
you want to express the number as negative, you use the – on the left side of the
number. The – symbol is called a sign. Therefore, if the number does not have the –
symbol, C++ (or the compiler) considers such a number as unsigned. In C++, if you
declare a variable that would represent a numeric value and you do not initialize (assign a
value to) such a variable, the compiler will consider that the variable can hold either a
signed or an unsigned value. If you want to let the compiler know that the variable should
hold only a positive value, you will declare such a variable as unsigned.
Data Types
In order to use a variable in your program, the compiler must be aware of it. Once the
compiler knows about a variable, it would reserve an amount of memory space for that
variable
Using its name, you can refer to a particular variable when necessary. Because there are
various types of variables a program can use, such as the employee's name, his home
address, the desired salary, years of experience, education level, etc for our employment
application analogy, the compiler needs a second piece of information for each variable
you intend to use. This piece of information specifies the amount of space that a variable
needs. You can see that, to store a character, such as an employee's gender (M or F) or
an answer as Y or N to a question, the compiler would certainly not need the same
amount of space to store the name of the last school attended by an employee.
A data type is an amount of space needed to store the information related to a particular
variable.
The name of a variable allows you and the compiler to refer to a particular category of
information in your program. The data type allows the compiler to reserve an adequate
amount of memory space for a variable. Because you are the one who writes a program,
you also tell the compiler the amount of memory space each particular variable will need.
Based on this, the C# language provides categories of data types used to specify this
amount of space needed for a variable.
As an alternative, you can provide only a name for the variable but let the compiler
specify its data type. To declare such a variable, you use the var keyword followed
by the name of the variable. This certainly would not be enough. For the compiler
to know how much space is necessary, you must provide a value for the variable
Providing a value for a variable is referred to as initializing it. This can be done for
declared with either a data type or the var keyword:
If you declare a variable using data type, the initialization could be optional
(depending on how you will access the variable)
If you declare a variable using the var keyword, you must initialize it
To initialize a variable, on the right side of its name, type the assignment operation, which
is =, followed by a value:
If you declare a variable using a data type, you must initialize it with an appropriate
value. When we study the data type, we will see what value is appropriate for what
data type
If you declare a variable using the var keyword, you can initialize it with almost any
type of value (of course there are exceptions). The purpose of using the var
keyword is to let the compiler decides what type the variable is. To make this decision, the
compiler refers to the type of value the variable was assigned with.
For illustrative purposes, in many lessons, we will use the var keyword to declare
variables. In practicality, don't abuse or overuse the var keyword. It can be
confusing. The beauty of var, which is one of its rules, is that you MUST initialize
its variable. This makes it possible to know the type of variable you are using. On
the other hand, if you declare too many variables with var and initialize them
with the same types of values, you could get confused with the type of data that
each of those variables is holding. So, use the var keyword sparingly: It can be a
beauty but, if overused, it can be confusing. The good news is that the compiler
knows exactly what it is doing and what it is asked to do.
Representing Numbers
A Bit
0 1
You can represent a piece of information with one of two states. This technique of
representing values is the same as the binary system. In the computer, it uses values 0
and/or 1, which themselves are called digits. The entity used to represent such a value is
called a binary digit; in its abbreviated form, it is called a bit (for binary digit). The bit
(binary digit) is the most fundamental representation of the computer's counting system.
Although the C# compiler recognizes a bit, you cannot store a variable in a bit. However,
eventually, you will be able to manipulate the information stored in a bit.
The single bit is used only to represent a tinny piece of information. To get effective numbers,
the computer combines the bits. The first combination of bits consists of grouping four
consecutive bits.
To count the bits, we number them starting at 0, followed by 1, 2, and 3. The count starts
with the most right bit:
The first bit, on the right side of the group, is called the Low Order bit or LO bit. This is
also called the least significant bit. The last bit, on the left side of the group, is called the
High Order bit or HI bit; it is also called the most significant bit. The bit on the right side is
counted as bit 0. The bit on the left side is counted as bit 3. The other bits are called by
their positions: bit 1 and bit 2.
Once again, each bit can have one of two states. Continuing with our illustration, when a cup is
empty, it receives a value of 0. Otherwise, it has a value of 1. On a group of four consecutive
bits, we can have the following combinations:
This combination is also a system that the computer uses to count bits internally.
Sometimes, in your program or in the help files, you will encounter a number that is less
than four bits, such as 10 or 01 or 101. The technique used to complete and fill out the
group of 4 bits consists of displaying 0 for each non-represented bit. The binary number
10 will be the same as 0010. The number 01 is the same as 0001. The number 101 is the
same as 0101. This technique is valuable and allows you to always identify a binary
number as a divider of 4.
When all bits of a group of 4 are 0, the combination has the lowest value, which is 0000.
Any of the other combinations has at least one 0 bit, except for the last one. When all bits
are 1, this provides the highest value possible for a group of 4 bits. The lowest value, also
considered the minimum value, can be represented in the decimal system as 0. The
highest value, also considered the maximum, can be expressed in decimal value as 2 4 (2
represents the fact that there are two possible states: 0 and 1; 4 represents the fact that
there are four possible combinations), which is 16. This produces 16 because 2 4 = 16.
As you can see, the binary system can appear difficult to read when a value combines various
bit representations. To make it easier, the computer recognizes the hexadecimal
representation of bits. Following the box combinations above, we can represent each 4-bit of
the sixteen combinations using the decimal, hexadecimal, and binary systems as follows:
0 0000 0
1 0001 1
2 0010 2
3 0011 3
5 0101 5
6 0110 6
7 0111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
When looking at a binary value represented by 4 bits, you can get its decimal or hexadecimal
values by referring to the table above. A group of four consecutive bits has a minimum and
maximum values on each system as follows:
Although the C# compiler recognizes a group of four consecutive bits, you cannot store
any variable in it. You can, however, manipulate the bits of the group.
A Byte
C# 3.0 Practical Learning 33
Introduction
A byte is a group or eight consecutive bits. The bits are counted from right to left starting
at 0:
The most right bit is bit 0; it is called the least significant bit. It is also referred to as the
Low Order bit, the LO bit, or LOBIT. The most left bit is bit 7; it is called the most
significant bit. It is also referred to as the High Order bit, the HI bit, or HIBIT. The other
bits are referred to following their positions:
Using the binary system, you can represent the byte using a combination of 0s and 1s.
When all bits have a value of 0, the byte is represented as 00000000. On the other hand,
when all bits have a value of 1, the byte is represented as 11111111. When the number
grows very large, it becomes difficult to read. Therefore, you can represent bits in groups
of four. Instead of writing 00000000, you can write 0000 0000. This makes the number
easier to read.
If you have the patience to create combinations of bits using the boxes as we did for the
group of 4, you would find out that there are 256 possible combinations. Another way to
find it out is by using the base 2 technique:
27 + 2 6 + 2 5 + 2 4 + 2 3 + 2 2 + 2 1 + 2 0
= 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= 255
Therefore, the maximum decimal value you can store in a byte is 255.
Remember that the byte with all bits having a value of 0 has its value set to 0. Since this
byte also holds a valid value, the number of combinations = 255 + 1 = 256.
When a byte is completely represented with 0s, it provides the minimum value it can hold; this
is 0000 0000, which is also 0. When all bits have a value of 1, which is 1111 1111, a byte
holds its maximum value that we calculated as 255 in the decimal system. As done with the
group of 4 bits, we get the following table:
The minimum storage area offered by the (Intel) computer is the byte. As you know
already, a byte is a group of 8 consecutive bits. The amount of memory space offered by
a byte can be used to store just a single symbol, such as those you see on your keyboard.
These symbols, also called characters, have been organized by the American Standard
Code for Information Exchange (ASCII) in a set list. But, ASCII uses only 128 decimal
numbers (based on a 7-bit format) to represent symbols counted from 0 to 127. To
compensate for the remaining 1 bit, IBM used it to organize special characters, foreign
language characters, mathematical symbols, small graphics, etc. Each one of these
characters has a decimal, a hexadecimal, and a binary equivalents.
Each one of the characters you see on your keyboard is represented as a numeric value,
but whether it appears as a number, a letter, or a symbol, each one of these is considered
a character. To display any character on your screen, you can pass it to Write() or
WriteLine() and include the character between single-quotes, as follows:
using System;
class Exercise
{
static void Main()
{
Console.WriteLine('n');
}
}
Characters
Besides the English language, other languages use other or additional characters that
represent verbal or written expressions.
class Exercise
{
static void Main()
{
var Gender = 'F';
class Exercise
{
static void Main()
{
char Gender = 'M';
Escape Sequences
An escape sequence is a special character that displays non-visibly. For example, you can
use this type of character to indicate the end of line, that is, to ask the program to
continue on the next line. An escape sequence is represented by a backslash character, \,
followed by another character or symbol. For example, the escape sequence that moves to
the next line is \n.
Escape
Name Description
Sequence
\f Form feed
To use an escape sequence, you can also first declare a char variable and initialize it with
the desired escape sequence in single-quotes.
A byte is an unsigned number whose value can range from 0 to 255 and therefore can be
stored in one byte. You can use it when you know a variable would hold a relatively small
value such as people's age, the number of children of one mother, etc. To declare a
variable that would hold a small natural number, use the byte keyword. Here is an
example:
byte Age;
You can initialize a byte variable when declaring it or afterwards. Here is an example that
uses the byte data type:
using System;
class ObjectName
{
static void Main()
{
Byte Age = 14;
Console.Write("Student Age: ");
Console.WriteLine(Age);
Age = 12;
Console.Write("Student Age: ");
Console.WriteLine(Age);
}
}
Make sure you do not use a value that is higher than 255 for a byte variable, you would
receive an error. When in doubt, or when you think that there is a possibility a variable
would hold a bigger value, don't use the byte data type as it doesn't like exceeding the
255 value limit.
C# 3.0 Practical Learning 37
Alternatively, you can also use the var keyword to declare the variable and initialize it with
a small number. Here is an example:
using System;
class Exercise
{
static void Main()
{
var Age = 14;
Console.Write("Student Age: ");
Console.WriteLine(Age);
Age = 12;
Console.Write("Student Age: ");
Console.WriteLine(Age);
}
}
Instead of a decimal number, you can also initialize an integral variable with a
hexadecimal value. When doing this, make sure the decimal equivalent is less than 255.
Here is an example:
using System;
class Exercise
{
static void Main()
{
var Number = 0xFE;
Console.Write("Number: ");
Console.WriteLine(Number);
}
}
namespace GeorgetownCleaningServices2
{
class Program
{
static void Main(string[] args)
{
byte Shirts;
byte Pants;
C# 3.0 Practical Learning 38
Shirts = 4;
Pants = 1;
Signed Byte
A byte number is referred to as signed if it can hold a negative of a positive value that
ranges from -128 to 127, which can therefore fit in a byte. To declare a variable for that
kind of value, use the sbyte keyword. Here is an example:
using System;
class NumericRepresentation
{
static void Main()
{
sbyte RoomTemperature = -88;
A Word
C# 3.0 Practical Learning 39
Introduction
A word is a group of 16 consecutive bits. The bits are counted from right to left starting at
0:
Considered as a group of 16 bits, the most right bit of a word, bit 0, is called the least
significant bit or Low Order bit or LO bit or LOBIT. The most left bit, bit 15, is called the
most significant bit or High Order bit or HI bit or HIBIT. The other bits are referred to
using their positions: bit 1, bit 2, bit 3, etc.
Considering that a word is made of two bytes, the group of the right 8 bits is called the
least significant byte or Low Order byte or LO byte or LOBYTE. The other group is called
the most significant byte or High Order byte or HI byte or HIBYTE.
The maximum binary value represented by a word is 1111 1111 1111 1111. To find out
the maximum decimal value of a word, you can use the base 2 formula, filling out each bit
with 1:
1*215+1*214+1*213 + 1*212 + 1*211 + 1*210 + 1*29 + 1*28 + 1*27 + 1*26 + 1*25 + 1*24 +
1*23 + 1*22 + 1*21 + 1*20
= 65535
To find out the maximum hexadecimal number you can store in a word, replace every group of
4 bits with an f or F:
f f f f
= 0xffff
= 0xFFFF
= 0XFFFF
Short Integers
A word, which is a group of 16 contiguous bits or 2 bytes, can be used to hold a natural
number. As we have studied, the maximum numeric value that can fit in a word is 65535.
To declare a variable for such a value, you can use the var keyword and initialize the
variable with a value between –32768 to 32767. Here is an example:
using System;
class Exercise
{
static void Main()
{
var SchoolEffective = 1400; // Number of Students
Since the byte is used for characters and very small numbers, whenever you plan to use a
number in your program, the minimum representation you should use is a word.
A natural number is also called an integer. If you want to declare the variable using a data
type, the smallest integer you can store in a word is declared with the short keyword.
Because a short integer is signed by default, it can store a value that ranges from –
32768 to 32767. Here is an example program that uses two short integers:
using System;
class Exercise
{
static void Main()
{
short NumberOfPages;
short Temperature;
NumberOfPages = 842;
Temperature = -1544;
Because a short integer handles numbers that are larger than the signed byte, any
variable you can declare for a signed byte can also be declared for a short variable.
If a variable must hold positive and relatively small numbers, it is referred as an unsigned
short integer. Such a variable can be declared using either the var of the ushort
keyword. An unsigned short integer can hold numbers that range from 0 to 65535 and
therefore can fit in 16 bits. Here is an example:
using System;
class NumericRepresentation
{
static void Main()
{
// These variables must hold only positive integers
ushort NumberOfTracks;
ushort MusicCategory;
NumberOfTracks = 16;
MusicCategory = 2;
namespace GeorgetownCleaningServices2
Shirts = 4;
Pants = 1;
OtherItems = 3;
A Double-Word
Introduction
The most right bit, bit 0, is called the Low Order bit or LO bit or LOBIT. The most left bit,
bit 31, is called the High Order bit or HI bit or HIBIT. The other bits are called using their
positions.
The group of the first 8 bits (from bit 0 to bit 7), which is the right byte, is called the Low
Order Byte, or LO Byte. It is sometimes referred to as LOBYTE. The group of the last 8 bits
(from bit 24 to bit 31), which is the left byte, is called the High Order Byte, or HI Byte or
HIBYTE. The other bytes are called by their positions.
The group of the right 16 bits, or the right Word, is called the Low Order Word, or LO
Word, or LOWORD. The group of the left 16 bits, or the left Word, is called the High Order
Word, or HI Word, or HIWORD.
The minimum binary number you can represent with a double-word is 0. The minimum
decimal value of a double-word is 0. To find out the maximum decimal value of a word,
you can use the base 2 formula giving a 1 value to each bit:
27 26 25 24 23 22 21 20
128 64 32 16 8 4 2 1
= 4,286,578,708
The minimum hexadecimal value you can store in a double-word is
0x00000000000000000000000000000000 which is the same as 0x0. To find out the maximum
hexadecimal number you can represent with a word, replace every group of 4-bits with an f or
F:
f f f f f f f f
To declare a variable that can hold large values, you can use the var keyword and
initialize the variable with the desired value. Here is an example:
using System;
class Exercise
{
static void Main()
{
var Population = 72394475;
2. To create a new application, on the main menu, click File -> New -> Project...
namespace GeorgetownCleaningServices3
{
class Program
{
static void Main(string[] args)
{
byte Shirts;
byte Pants;
ushort OtherItems;
Shirts = 4;
Pants = 0;
OtherItems = 3;
Signed Integers
A double-word is large enough to contain double the amount of data that can be stored in
a word. This is equivalent to 32 bits or 4 bytes or 4,294,967,295. Therefore, a double-
word is used for large numbers that would not fit in a word.
To use a variable that would hold quite large numbers, besides the var keyword, you can
declare it using the int keyword. A variable declared as int can store values between –
2,147,483,648 and 2,147,484,647 negative or positive, that can fit in 32 bits.
Here is an example:
using System;
class Exercise
{
static void Main()
{
int CoordX;
int CoordY;
CoordX = 12;
CoordY = -8;
If you declare an integer variable using the var keyword and initialize it with a value lower
than 2,147,484,647, the compiler concludes that the memory needed to store that
variable is 32 bits:
class Exercise
{
static void Main()
{
var Number = 0xF0488EA;
Console.Write("Number: ");
Console.WriteLine(Number);
}
}
Unsigned Integers
If the variable must hold only positive natural numbers, you can declared it using the uint
keyword. The uint keyword is used to identify a 32-bit positive integer whose value
would range from 0 to 2,147,484,647. Here is an example:
using System;
class Exercise
{
static void Main()
{
C# 3.0 Practical Learning 48
uint DayOfBirth;
uint MonthOfBirth;
uint YearOfBirth;
DayOfBirth = 8;
MonthOfBirth = 11;
YearOfBirth = 1996;
Console.Write(MonthOfBirth);
Console.Write("/");
Console.Write(DayOfBirth);
Console.Write("/");
Console.Write(YearOfBirth);
Console.WriteLine();
}
}
namespace GeorgetownCleaningServices3
{
class Program
{
static void Main(string[] args)
{
byte Shirts;
byte Pants;
ushort OtherItems;
uint OrderDay;
uint OrderMonth;
uint OrderYear;
Shirts = 4;
Pants = 0;
OtherItems = 3;
OrderDay = 15;
OrderMonth = 7;
OrderYear = 2002;
A Quad-Word
Introduction
Sometimes you may want to store values that a double-word cannot handle. To store a
very large number in a variable, you can consider a combination of 64 bits. The group can
also be referred to as a quad-word. A quad-word is so large it can store numbers in the
range of –9,223,372,036,854,775,808 and 9,223,372,036,854,775,807.
If you declare an integer variable using the var keyword and initialize it with a value
between 2,147,484,647 and 9,223,372,036,854,775,807, the compiler concludes that the
memory needed to store that variable is 64 bits:
If you want to use a variable that can hold very large numbers that would require up to 64
bits, you can declare it using either the var or the long keyword.
In C++, the long data type is 32 bits while in C#, the long data type is 64
bits.
As stated previously, if you initialize the variable with a value lower than 2,147,484,647,
the compiler would allocate 32 bits of memory for it. If you initialize the variable with a
value between 2,147,484,647 and 9,223,372,036,854,775,807, the compiler would
allocate 64 bits of memory for it. If the value is higher than 9,223,372,036,854,775,807,
which is too large, the compiler would present an error:
class Exercise
{
static void Main()
{
var CountryArea = 5638648;
As mentioned for other integral types, you can initialize a long variable with a
hexadecimal value.
Although the long data type is used for large number, it mainly indicates the amount of
space available but you do not have to use the whole space. For example, you can use the
long keyword to declare a variable that would hold the same range of numbers as the
short, the int, or the uint data types. If you declare a variable as long but use it for
small numbers that don't require 64 bits, the compiler would allocate the appropriate
amount of space to accommodate the values of the variable. Consequently, the amount of
space made available may not be as large as 64 bits. If you insist and want the compiler
C# 3.0 Practical Learning 52
to reserve 64 bits, when assigning a value to the variable, add an L suffix to it. Here is an
example that uses space of a long data type to store a number that would fit in 32 bits:
using System;
class NumericRepresentation
{
static void Main()
{
long CountryArea;
CountryArea = 5638648L;
Therefore, keep in mind that an int, a uint, a short, or a ushort can fit in a long
variable.
You can use a combination of 64 bits to store positive or negative integers. In some cases,
you will need a variable to hold only positive, though large, numbers. To declare such a
variable, you can use the ulong data type. A variable declared as ulong can handle
extremely positive numbers that range from 0 to 18,446,744,073,709,551,615 to fit in 64
bits.
Real Numbers
Introduction
A real number is a number that displays a decimal part. This means that the number can
be made of two sections separated by a symbol that is referred to as the Decimal
Separator or Decimal Symbol. This symbol is different by language, country, group of
languages, or group of countries. In US English, this symbol is the period as can be
verified from the Regional (and Language) Settings of the Control Panel:
Floating-Point Numbers
The integers we have used so far have the main limitation of not allowing decimal values.
C# provides floating values that would solve this problem. The most fundamental floating
variable is declared with the float keyword. A variable declared a float can store real
numbers that range from ±1.5 × 10−45 to ±3.4 × 1038 with a precision of 7 digits in 32
bits. Here is an example:
using System;
class NumericRepresentation
{
static void Main()
{
float Distance;
}
}
Double-Precision Numbers
When a variable is larger than the float can handle and requires more precision, you
should declare it using either the var or the the double keyword. Here is an example:
C# 3.0 Practical Learning 54
using System;
class Exercise
{
static void Main()
{
var Number = 62834.9023;
Console.Write("Number: ");
Console.WriteLine(Number);
}
}
A variable declared as double uses 64 bits to store very large numbers ranging from
±5.0 × 10−324 to ±1.7 × 10308 with a precision of 15 or 16 digits. Because the double
data type provides a better result with a better precision than the float, whenever you
declare a variable using either the var or the float keyword and assign it a value, the
compiler allocates 64 bits to store the values of the variable. If you insist on the variable
being treated as float, when assigning it a value, add an F suffix to the value. Here is an
example:
using System;
class NumericRepresentation
{
static void Main()
{
float Distance;
Distance = 248.38F;
Console.Write("Distance = ");
Console.Write(Distance);
Console.WriteLine("km\n");
}
}
Remember that if you declare the variable as var and want to treat it as a value with
single precision, add an F suffix to the value assigned to it. Here is an example:
using System;
class Exercise
{
static void Main()
{
var Number = 62834.9023F;
Console.Write("Number: ");
Console.WriteLine(Number);
On the other hand, if you want a value to be treated with double-precision, add a D suffix
to it. Here is an example:
using System;
class Exercise
{
static void Main()
{
var Number = 62834.9023D;
Console.Write("Number: ");
Console.WriteLine(Number);
}
}
namespace GeorgetownCleaningServices3
{
class Program
{
static void Main(string[] args)
{
byte Shirts;
byte Pants;
ushort OtherItems;
uint OrderDay;
uint OrderMonth;
uint OrderYear;
double MondayDiscount;
Shirts = 4;
Pants = 0;
OtherItems = 3;
OrderDay = 15;
OrderMonth = 7;
OrderYear = 2002;
MondayDiscount = 0.25D; // 25%
Decimal
The decimal data type can be used to declare a variable that would hold significantly
large values that can be stored in a combination of 128 bits. You declare such a variable
using the decimal keyword. The values stored in a decimal variable can range from
±1.0 × 10−28 to ±7.9 × 1028 with a precision of 28 to 29 digits. Because of this high level
of precision, the decimal data type is suitable for currency values.
After declaring a decimal variable, you can initialize it with a natural number. To indicate
that the variable holds a decimal value, when initializing it, add an M suffix to its value.
Here is an example:
using System;
class NumericRepresentation
{
static void Main()
C# 3.0 Practical Learning 57
{
decimal HourlySalary;
HourlySalary = 24.25M;
As seen in previous sections and this one, when declaring and initializing a real variable,
the suffix you give to its assigned value indicates to the compiler the actual type of value
and the type of memory that would be allocated for the variable:
If the value receives an F suffix, it is considered a floating point number with single
precision
If the value receives a D suffix, it is considered a floating point number with double
precision
namespace GeorgetownCleaningServices3
{
class Program
{
static void Main(string[] args)
{
byte Shirts;
decimal PriceOneShirt;
byte Pants;
decimal PriceAPairOfPants;
ushort OtherItems;
decimal PriceOtherItems;
uint OrderDay;
uint OrderMonth;
uint OrderYear;
double MondayDiscount;
Shirts = 5;
PriceOneShirt = 0.95M;
Pants = 2;
PriceAPairOfPants = 1.95M;
OtherItems = 3;
PriceOtherItems = 4.55M;
OrderDay = 15;
OrderMonth = 7;
OrderYear = 2002;
MondayDiscount = 0.25D; // 25%
Strings
A string is an empty space, a character, a word, or a group of words that you want the
compiler to consider "as is", that is, not to pay too much attention to what the string is
made of, unless you explicitly ask it to. This means that, in the strict sense, you can put in
a string anything you want.
Primarily, the value of a string starts with a double quote and ends with a double-quote.
An example of a string is "Welcome to the World of C# Programming!". You can include
such a string in Console.Write() to display it on the console. Here is an example:
using System;
class Exercise
{
static void Main()
C# 3.0 Practical Learning 61
{
Console.WriteLine("Welcome to the World of C# Programming!");
}
}
Sometimes, you will need to use a string whose value is not known in advance. Therefore,
you can first declare a string variable. To do this, use either the var or the string
keyword followed by a name for the variable. The name will follow the rules we defined
above. When declaring a string variable, you can initialize it with an empty space, a
character, a symbol, a word, or a group of words. The value given to a string must be
included in double-quotes. Here are two examples:
using System;
class Exercise
{
static void Main()
{
var Team = "Real Madrid";
string Country = "Guinée Equatoriale";
namespace GeorgetownCleaningServices3
{
class Program
{
static void Main(string[] args)
byte Shirts;
decimal PriceOneShirt;
byte Pants;
decimal PriceAPairOfPants;
ushort OtherItems;
decimal PriceOtherItems;
uint OrderDay;
uint OrderMonth;
uint OrderYear;
double MondayDiscount;
A date is a unit that measures the number of years, months, or days elapsed in a specific
period. A time is a unit that counts the number of seconds that have elapsed since
midnight of the day considered. Although dates and times are large subjects that would
require a detailed study, at this time, we will consider them in simple terms.
To declare a variable that would hold date or time values, use the DateTime data type.
using System;
class NumericRepresentation
{
static void Main()
{
DateTime DateHired;
}
}
The .NET Framework sets its starting periodic date to January 1, 0001 at midnight
(12:00:00 or 0:00 AM). If not assigned a specific value (in future lessons, we will learn
that this is equivalent to declaring a variable using the default constructor), the variable is
initialized to 1/1/0001 at midnight.
Objects
class Exercise
{
static void Main()
{
var EmployeeName = "Ernestine Lamb";
object Address = "10244 Lockwood Drive";
A variable declared with object can embrace almost any value. This means that, when
initializing the variable, you can use any of the types of values we have seen so far. Here
are examples:
using System;
class Program
{
static void Main()
{
object PropertyNumber = "293749";
object PropertyType = 'S';
object Stories = 3;
object Bedrooms = 4;
object Value = 425880;
Constants
Custom Constants
Suppose you intend to use a number such as 39.37 over and over again. Here is an
example:
using System;
class Exercise
{
static void Main()
{
double Meter, Inch;
Meter = 12.52D;
Inch = Meter * 39.37D;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
}
}
If you use this 39.37 many times in your program, at one time, you may make a mistake
and type it as 3937 or 3.937 or else. Consider the following program:
using System;
class Exercise
{
static void Main()
{
double Meter, Inch;
Meter = 12.52D;
Inch = Meter * 39.37;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
C# 3.0 Practical Learning 66
Meter = 12.52D;
Inch = Meter * 3.937;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
Meter = 12.52D;
Inch = Meter * 393.7;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
}
}
12.52m = 49.29124in
12.52m = 4929.124in
Because of mistakes in the way to represent the number, the same calculation produces
different results. To make sure that this is unlikely, you can instead use a variable that
holds the value. Then, when you need that value, you can access the variable instead of
the value itself. A number such as 39.37 is called a constant.
A constant is a value that never changes such as 244, "ASEC Mimosa", 39.37, or True.
These are constant values you can use in your program any time. You can also declare a
variable and make it a constant; that is, use it so that its value is always the same.
To create a constant, type the const keyword to its left. When declaring a constant, you
must initialize it with an appropriate value. Here is an example:
const double ConversionFactor = 39.37D;
Once a constant has been created and it has been appropriately initialized, you can use its
name where the desired constant would be used. Here is an example of a constant
variable used various times:
using System;
class Exercise
{
static void Main()
{
const double ConversionFactor = 39.37D;
double Meter, Inch;
Meter = 12.52D;
Inch = Meter * ConversionFactor;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
Meter = 12.52D;
Inch = Meter * ConversionFactor;
Console.Write(Meter);
Console.Write("m = ");
Console.Write(Inch);
Console.WriteLine("in\n");
}
}
12.52m = 492.9124in
12.52m = 492.9124in
Notice that, this time, the calculation is more accurate. Also, this time, if you mistype the
name of the variable in an operation, you would receive a compiler error, giving you the
time to fix it.
To initialize a constant variable, the value on the right side of the assignment operator "="
must be a constant or a value that the compiler can determine as constant. Instead of
using a known constant, you can also assign it another variable that has already been
declared as constant.
Built-in Constants
There are two main categories of constants you will use in your programs. You can create
your own constant as we saw above. The C# language also provides various constants.
Some constants are part of the C# language. Some other constants are part of the .NET
Framework. Before using a constant, of course, you must first know that it exists. Second,
you must know how to access it. A constant that is part of the C# language can be
accessed anywhere in your code. Those constant are normally defined in the System
namespace. Other constant are defined in various appropriate namespaces.
null: The null keyword is a constant used to indicate that a variable doesn't hold a known
value
PI: PI is a constant used as the ratio of the circumference of a circle to its diameter. PI is
defined in Math. To use it, you would type Math.PI.
Fundamentals of Classes
Introduction
In the previous two lessons, to use a variable, we were declaring it using either var or a
known and simple data type. For example, we could use an integer to declare a variable
that represented the number of bedrooms of a house. Here is an example:
using System;
class Program
{
static void Main()
{
int bedrooms = 3;
}
}
As opposed to a simple variable, in C#, you can use one or more variables to create a
more complete or complex object.
Instead of only one file, you can create a program with many of them. Each file can
contain different instructions that, when put together, can create an application as
complete as possible. To create a code file, on the main menu, you can click Project ->
Add New Item... In the Templates list, click Code File, accept or change the name of the
file. You can omit the .cs extension. If you do, a file with the extension .cs would be
added.
Creating a Class
A class is created in a code file. As such, you can include it in the first file of your project.
Here is an example:
using System;
class House
{
}
class Program
{
static void Main()
{
int bedrooms = 3;
}
}
You can also create a class in its own file. To assist you with this, Microsoft Visual C#
provides a wizard. To use it, on the main menu, you can click Project -> Add Class... or
Project -> Add New Item... In the Templates list, click Class. In the Name text box, accept
or change the default name and click Add. A new file named after the class with the .cs
extension would be added to your project.
When a project is made of various files, each file is represented by a tab in the top section
of the Code Editor:
1. To create a new class, on the main menu, click Project -> Add Class...
2. In the Add New Item dialog box, change the name to DepartmentStore and click
Add
To assist you with managing the various classes of a project, Microsoft Visual C# includes
various tools and windows. One of the windows you can use is called the Class View. To
display it, on the main menu, you can click View -> Class View:
Under the toolbar, another bar made of a combo box and a button allow you to search.
The main top section of the Class View is made of various nodes. To expand a node, you
can click its + button. To collapse a node, you can click its - button. The top node displays
the name of the project. Under the project node, the names of classes display. The
bottom section of the Class View is used to display the members of a class. To see the
members of a class, you can click it in the top window. Here is an example:
To add a new class, besides the main menu, you can right-click the name of the project in
the Class View, position the mouse on Add, and click Class...
Like any normal variable, to use a class in your program, you can first declare a variable
for it. Like the variables we introduced in the previous lesson, to declare a variable of a
class, you can use the var keyword. Alternatively, you can type its name followed by a
class House
{
}
class Program
{
static void Main()
{
var property . . .
}
}
Or the following:
using System;
class House
{
}
class Program
{
static void Main()
{
House property;
}
}
The variables we have declared so far are called value variables. This is because such
variables of primitive types hold their value. The C# language supports another type of
variable. This time, when you declare the variable, its name does not hold the value of the
variable; it holds a reference to the address where the actual variable is stored in memory.
This reference type is the kind used to declare a variable for a class.
To use a variable as reference, you must initialize it using an operator called new. Here is
an example:
using System;
class House
{
}
class Program
{
static void Main()
{
var Property = new House();
}
}
If you are using the name of the class instead of var to declare the variable, you can first
declare it. Then, on another line, you can allocate memory for it using the new operator.
Here is an example:
C# 3.0 Practical Learning 73
using System;
class House
{
}
class Program
{
static void Main()
{
House Property;
In C#, as well as Visual Basic, if you create a class in any of the files that belong to the
same project, the class is made available to all other files of the same project.
Sharing a Class
Unlike its sisters the C and the C++ languages, C# was developed with the idea of
working complementarily with other languages such as C++/CLI, Visual Basic, and J#. In
other words, code from these other languages should be able to "read" or access code
written in a C# application. To make this possible, a C# class can be created as a public
object.
If you want your class to be accessible to code written in other languages, precede the
class keyword with public when creating it. Here is an example:
using System;
{
static void Main()
{
var Number = 244;
var Thing = "Vehicle";
Console.WriteLine(Number);
Console.WriteLine(Thing);
}
}
Garbage Collection
When you initialize a variable using the new operator, you are in fact reserving some space
in the heap memory. The memory is "allocated" for the variable. When that variable is no
longer needed, such as when your program closes, it (the variable) must be removed from
memory and the space it was using can be made available to other variables or other
programs. This is referred to as garbage collection. In the past, namely in C/C++, this was
The .NET Framework solves the problem of garbage collection by "cleaning" the
memory after you. This is done automatically when necessary so that the programmer
doesn't need to worry about this issue.
Class' Fields
Introduction
The section between the curly brackets, { and }, of a class is referred to as its body. In
the body of a class, you can create a list of the parts that make up the class. Each of
these parts must be a complete variable with a name and a data type. For example, here
are the characteristics that make up a house, declared as the parts of the above Book
class and each declared as a variable:
public class House
{
string PropertyNumber;
char PropertyType;
byte Stories;
uint bedrooms;
decimal Value;
}
The variables declared in the body of a class are referred to as its member variables and
each member variable is referred to as a field. The fields can be any type we have seen in
the previous lesson. When creating a class, it is your job to decide what your object is
made of.
Imagine you want to write a (console-based) program for a department store and the
customer has given you a preliminary catalog as follows:
Stock: 681432
Stock #: 759470 Stock #: 482746
Women Python Print Leather
Men Escalade Slip-On Shoes Boys Leather Bomber Jacket
Bag
$89.85 $255.50
$75.00
Each item in this catalog is represented by its Stock number, its name or description, and
its price. Based on this, you can create a class that represents each item.
namespace DepartmentStore1
{
class DepartmentStore
{
long StockNumber;
char Category;
string ItemName;
decimal UnitPrice;
C# 3.0 Practical Learning 76
}
}
Private Members
The parts of an object fall into two main categories: those you can touch and those you
don't have access to. For example, for a car parked at the mall, you can see or touch its
doors and its tires but you don't see its engine or its spare tire, you don't even know if it
has one. The parts of an object that you have access to are referred to as public. Those
you can't see or touch are referred to as private.
A C# class also recognizes that some parts of a class can be made available to other
classes and some other parts can be hidden from other classes. A part that must be
hidden from other classes is private and it can be declared starting with the private
keyword. If you declare a member variable and want to make it available to other classes,
you must start its name with the public keyword. The public and private keywords
are referred to as access level.
By default, if you declare a member variable (or anything else) in a class but don't specify
its access level, the member is considered private and cannot be accessed from outside,
that is by a non-member, of that class. Therefore, to make a member accessible by other
classes, you must declare it as public.
You can use a mix of public and private members in a class and there is no rule on which
access level should be listed first or last. Here are examples:
public class House
{
string PropertyNumber;
public char PropertyType;
byte Stories;
public uint bedrooms;
private decimal Value;
}
Just keep in mind that if you omit or forget the access level of a member of a class, the
member is automatically made private. To reduce confusion as to what member is public
or private, you should always specify the access level of a member variable.
public class House
{
public string PropertyNumber;
public char PropertyType;
public byte Stories;
public uint Bedrooms;
public decimal Value;
}
Internal Members
We have seen that the public keyword is used to let objects of the same program and
objects of other programs access the public member. The private keyword is used to let
only members of a class access the (private) member of the class. If you want to create a
member of a class so that only objects of the same program can access that member, you
can mark it with the internal keyword. The differences between these keywords can be
resumed as follows:
Initializing an Object
Introduction
After declaring an instance of a class, you can access each of its members and assign it
the desired value. Here is an example:
using System;
Property.PropertyNumber = 283795;
Property.PropertyType = "Single Family";
Property.Bedrooms = 4;
Property.Value = 652880;
}
}
Once a member variable has been initialized, you can use the period operator to access it
and retrieve its value:
using System;
Property.PropertyNumber = 283795;
Property.PropertyType = "Single Family";
Property.Bedrooms = 4;
Property.Value = 652880;
1. To make public the members of the DepartmentStore class, type the public
keyword to their left:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DepartmentStore1
{
class DepartmentStore
{
public long StockNumber;
public char Category;
public string ItemName;
public double UnitPrice;
}
}
2. To access the Program.cs file, click its tab above the Code Editor
namespace DepartmentStore1
{
class Program
{
static void Main(string[] args)
{
DepartmentStore dptStore = new DepartmentStore();
dptStore.StockNumber = 437876;
dptStore.Category = 'W';
dptStore.ItemName = "Scoop Neck Dress";
dptStore.UnitPrice = 148.00D;
Console.WriteLine("Department Store");
Console.Write("Stock #: ");
Console.WriteLine(dptStore.StockNumber);
Console.Write("Category: ");
Console.WriteLine(dptStore.Category);
Console.Write("Name: ");
Console.WriteLine(dptStore.ItemName);
Console.Write("Unit Price: ");
Console.WriteLine(dptStore.UnitPrice);
Console.WriteLine();
}
}
}
We saw that, to use a class, you could first declare a variable for it and initialize it.
Fortunately, you don't have to use a class to initialize an object. You can declare a variable
that resembles an instance of a class and initialize it as you see fit. This is referred to as
an anonymous type. To use it, declare the variable using the var keyword and use the
new operator to allocate memory for it. Instead of using the name of a class, type an
opening and a closing curly brackets after the new operator. In the curly brackets, state a
name for each member as if it were the member of the class and initialize each member
variable with the desired value. After the closing curly bracket, end the declaration with a
semi-colon. Here is an example:
using System;
Pages = 1074,
Cover = "Hard Back"
};
}
}
After initializing the anonymous type, you can access each one of its members using the
name of the variable followed by the period operator, and followed by the member
variable. Here is an example:
using System;
Remember that spreading the declaration on many lines only makes it easy to read.
Otherwise, you can as well include everything on the same line.
using System;
Introduction
When you create a class, the fields are meant to describe it. For a class named House,
such aspects as the number of bedrooms, the property type, or its value, are used to
describe it:
public class House
{
public char PropertyType;
public uint Bedrooms;
}
Besides the characteristics used to describe it, an object can also perform actions or
assignments. An action performed by a class is called a method. A method is simply a
section of code that takes care of a particular detail for the functionality of the class. To
void Display()
{
}
}
If the method will be accessed only by members of the same class, you can mark it
as private or not mark it with an access keyword
If the method will be accessed by members of the class and other parts of the
same program but not outside of the program, mark it with the internal keyword
In the method can be accessed by the members of the same class, other parts of
the same program, and other parts of other programs, mark it as public
After creating a method, in its body delimited by its curly brackets, you can define the
desired behavior. For example, you can write the member variables in the parentheses of
Console.Write() or Console.WriteLine(). Here are examples:
In the same way, you can create as many methods as you want in a class. To assist you
with managing the methods of a class, the Code Editor is equipped with two combo boxes.
If you select an item from the Members combo box, the caret would be displayed on its
declaration in the file.
The Solution Explorer is a window that displays the file names and other items used in
your project. The items of this window display in a tree. To expand a node, you can click
its + button. To collapse it, click its - button. To explore an item, you can double-click it.
The result depends on the item you double-clicked.
The Solution Explorer can be used to create and add a new class or a new item to the
current project. It can also be used to add a another project to the current project. To
Remember that you can also perform any of these operations from the Project category of
the main menu.
Besides adding new items to the project, you can also use the Solution Explorer to build
the project or change its properties. If you add one or more other project(s) to the current
one, one of the project must be set as the default. That project would be the first to come
up when the user executes the application. By default, the first project created is set as
the default. If you have more than one project, to set the default, right-click the name of
the desired project in Solution Explorer and click Set As StartUp Project.
The Solution Explorer also allows you to rename or delete some of the items that belong
to your project.
namespace DepartmentStore1
{
class DepartmentStore
{
public long StockNumber;
Console.Write("Stock #: ");
Console.WriteLine(StockNumber);
Console.Write("Category: ");
Console.WriteLine(Category);
Console.Write("Name: ");
Console.WriteLine(ItemName);
Console.Write("Unit Price: ");
Console.WriteLine(UnitPrice);
Console.WriteLine();
}
}
}
namespace DepartmentStore1
{
class Program
{
static void Main(string[] args)
{
DepartmentStore dptStore = new DepartmentStore();
dptStore.CreateItem();
dptStore.ShowItem();
}
}
}
Accessing a Method
After creating a method, you can access it outside of its class. You do this following the
same rules used to access a field, using the period operator. Unlike a field, the name of a
class must be followed by parentheses. Here is an example:
using System;
Property.PropertyType = 'S';
Property.Bedrooms = 4;
Property.Display();
}
}
Static Fields
Each one of these instances gives you access to the members of the class but each
instance holds the particular values of the members of its instance. Consider the results of
the following program:
using System;
Console.WriteLine("Book Characteristics");
Console.Write("Title: ");
Console.WriteLine(First.Title);
Console.Write("Author: ");
Console.WriteLine(First.Author);
Console.Write("Year: ");
Console.WriteLine(First.YearPublished);
Console.WriteLine("Book Characteristics");
Console.Write("Title: ");
Console.WriteLine(Second.Title);
Console.Write("Author: ");
Console.WriteLine(Second.Author);
Console.Write("Year: ");
Console.WriteLine(Second.YearPublished);
Console.Write("Pages: ");
Console.WriteLine(Second.NumberOfPages);
Console.Write("Cover: ");
Console.WriteLine(Second.CoverType);
Console.WriteLine();
}
}
Book Characteristics
Title: C# First Step
Author: Alexandra Nyango
Year: 2004
Pages: 604
Cover: P
All of the member variables and methods of classes we have used so far are referred to as
instance members because, in order to access them, you must have an instance of a class
declared in another class in which you want to access them.
C# allows you to declare a class member and refer to it regardless of which instance of an
object you are using. Such a member variable is called static. To declare a member
variable of a class as static, type the static keyword on its left. Whenever you have a
static member, in order to refer to it, you must "qualify" it in the class in which you want
to call it. Qualifying a member means you must specify its class. Here is an example:
using System;
Console.WriteLine("Book Characteristics");
Console.Write("Title: ");
Console.WriteLine(Book.Title);
Console.Write("Author: ");
Console.WriteLine(Book.Author);
Console.Write("Year: ");
Console.WriteLine(First.YearPublished);
Console.Write("Pages: ");
Console.WriteLine(First.Pages);
Console.Write("Cover: ");
Console.WriteLine(First.CoverType);
Console.WriteLine("Book Characteristics");
Console.Write("Title: ");
Console.WriteLine(Book.Title);
Console.Write("Author: ");
Console.WriteLine(Book.Author);
Console.Write("Year: ");
Console.WriteLine(Second.YearPublished);
Console.Write("Pages: ");
Console.WriteLine(Second.Pages);
Console.Write("Cover: ");
Console.WriteLine(Second.CoverType);
Console.WriteLine();
}
}
Notice that when a member variable has been declared as static, you don't need an
instance of the class to access that member variable outside of the class. Based on this, if
you declare all members of a class as static, you don't need to declare a variable of their
class in order to access them. In the following example, the Title and Author fields of the
Console.WriteLine("Book Characteristics");
Console.WriteLine("Title: ");
Console.WriteLine(Book.Title);
Console.WriteLine("Author: ");
Console.WriteLine(Book.Author);
Console.WriteLine("Book Characteristics");
Console.WriteLine("Title: ");
Console.WriteLine(Book.Title);
Console.WriteLine("Author: ");
Console.WriteLine(Book.Author);
Console.ReadLine();
}
}
You can also declare member variables of the main class as static. If you are referring to a
static member variable in the same class in which it was declared, you don't have to
qualify it. Here is an example:
using System;
Length = 22.55;
Width = 20.25;
Console.WriteLine("\nRectangle 1");
Console.Write("Length: ");
Console.WriteLine(Length);
Console.Write("Width: ");
Console.WriteLine(Width);
C# 3.0 Practical Learning 91
Length = 254.04;
Width = 408.62;
Console.WriteLine("\nRectangle 2");
Console.Write("Length: ");
Console.WriteLine(Length);
Console.Write("Width: ");
Console.WriteLine(Width);
Console.WriteLine();
}
}
Static Methods
Like a member variable, a method of a class can be defined as static. Consequently, this
particular method can access any member of the class regardless of the instance if there
are many instances of the class declared.
To define a method as static, type the static keyword to its left. Here is an example:
using System;
The ReadLine(), the Write(), and the WriteLine() methods of the Console class that
we have used so far are examples of static methods.
Static Classes
A static class:
2. Is a class whose members must be created as static. In other words, you cannot
add a non-static member to a static class: all members, except for constants, must
be static
To create a static class, precede the class keyword with the static keyword. Based on
the above two rules, here is an example:
using System;
namespace Staticity
{
public static class Square
{
public static double Side;
Console.WriteLine("Square Characteristics");
Console.Write("Side: ");
Console.WriteLine(Square.Side);
C# 3.0 Practical Learning 93
Console.Write("Perimeter: ");
Console.WriteLine(Square.Perimeter());
Console.Write("Area: ");
Console.WriteLine(Square.Area());
}
}
}
Constants
Unlike C/C++, in C#, you can create a constant variable in a class. As done in Lesson 2
when studying variables, to declare a constant variable, type the const keyword to
the left of the variable. Once again, when declaring a constant, you must initialize it with
an appropriate constant value.
this Instance
If a class contains fields and methods, the (non-static) field members are automatically
available to the method(s) of the class, even fields that are private. When accessing a field
or a method from another method of the class, to indicate that the member you are
accessing belongs to the same class, you can precede it with the this member and the
period operator. Here are examples:
public class House
{
internal char PropertyType;
internal uint Bedrooms;
When using the this member variable (in C/C++, it is a pointer), you can access any
member of a class within any method of the same class. There are rules you must observe
when using this:
this cannot be used in a class A to access a member of class B. The following will
cause an error:
public class Exercise
{
static void Main()
{
House property = new House();
property.PropertyType = 'S';
property.Bedrooms = 4;
this.property.Display();
}
}
1. Access the DepartmentStore.cs file and, to use this, change the class as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DepartmentStore1
{
class DepartmentStore
{
public long StockNumber;
public char Category;
public string ItemName;
public double UnitPrice;
Console.Write("Stock #: ");
Console.WriteLine(this.StockNumber);
Console.Write("Category: ");
Console.WriteLine(this.Category);
Console.Write("Name: ");
C# 3.0 Practical Learning 95
Console.WriteLine(this.ItemName);
Console.Write("Unit Price: ");
Console.WriteLine(this.UnitPrice);
Console.WriteLine();
}
}
}
Namespaces
Introduction
A namespace is a section of code that is identified with a specific name. The name could
be anything such as somebody's name, the name of the company's department, or a city.
To create a namespace, you start with the namespace keyword followed by the name of
the section. Like a class, the section that is part of a namespace starts with an opening
curly bracket "{" and ends with a closing curly bracket "}". Here is an example:
namespace Business
{
}
Between the curly brackets, you can type anything that is part of the namespace. For
example, you can create a class inside of a namespace. Here is an example:
namespace Business
{
class House
{
}
}
1. Start Microsoft Visual C# 2005 and create a new Console Application named
RealEstate1
2. To create a new class, in the Class View, right-click the name of the project,
position the mouse on Add and click Class...
using System;
namespace RealEstate1
{
public class House
{
public string PropertyNumber;
public char PropertyType;
public uint Stories;
public uint Bedrooms;
public float Bathrooms;
public double Value;
}
}
After creating the necessary members of a namespace, you can use the period operator to
access an item that is part of the namespace. To do this, in the desired location, type the
name of the namespace, followed by a period, followed by the desired member of the
namespace. Here is an example:
using System;
namespace Business
{
public class House
{
public string PropertyNumber;
public decimal Price;
}
}
property.PropertyNumber = "D294FF";
property.Price = 425880;
Namespace Nesting
You can create one namespace inside of another namespace. Creating a namespace inside
of another is referred to as nesting the namespace. The namespace inside of another
namespace is nested. To create a namespace inside of another, simply type it as you
would create another namespace. Here is an example:
namespace Business
{
public class House
{
public string PropertyNumber;
public decimal Price;
}
namespace Dealer
{
}
}
In the example above, the Dealer namespace is nested inside of the Business namespace.
After creating the desired namespaces, nested or not, you can create the necessary
class(es) inside of the desired namespace. To access anything that is included in a nested
namespace, you use the period operator before calling a member of a namespace or
before calling the next nested namespace. Here is an example:
using System;
namespace Business
{
public class House
{
public string PropertyNumber;
public decimal Price;
}
namespace Dealer
{
public class Car
{
public decimal Price;
}
}
}
property.PropertyNumber = "D294FF";
C# 3.0 Practical Learning 99
property.Price = 425880;
In the same way, you can nest as many namespaces inside of other namespaces as you
judge necessary.
Introduction
To make programming in C# a little easier, many classes ship with it and they are created
in various namespaces of the .NET Framework. Each namespace in C# is used to
provide a specific set of classes. The most regularly used namespace in the C# language
is called System. Inside of the System namespace is a class called Console. The Console
class is used to display things on the console screen also called the DOS window.
The Console class contains static methods to display information on the screen or to
retrieve information from the user who types it in the DOS window. The method that is
used to display text on the screen is called Write. To use the Write() method, inside of
the parentheses, type the sentence between double-quotes. Here is an example:
public class Exercise
{
static void Main()
{
}
}
Using a Namespace
We saw that, to call an object or a method that is part of a namespace, you must "qualify"
that method or object using the period operator. Instead of using this approach, if you
already know the name of a namespace that exists or has been created in another file,
you can use a special keyword to indicate that you are using a namespace that is defined
somewhere. This is done with the using keyword. To do this, on top of the file
(preferably), type using followed by the name of the namespace.
With the using keyword, you can include as many external namespaces as necessary.
Access the Program.cs file and notice that it has a using declaration
Introduction
In C# (unlike many other languages such as C/C++, Pascal, etc), all of the data types we
have used so far are in fact complete classes. This means that they are equipped with
methods. These classes are defined in the System namespace. The classes of these data
types are defined as:
Equivalent Equivalent .
C# Data Type C# Data Type
.NET Class NET Class
This means that, if you don't want to use the data types we have reviewed so far, you can
use the class that is defined in the System namespace. To use one of these types, type
the System namespace followed by a period. Then type the equivalent class you want to
use. Here is an example:
class Operations
{
public double Addition()
{
System.Double a;
System.Double b;
System.Double c;
a = 128.76;
b = 5044.52;
c = a + b;
return c;
}
}
Because the regular names of data types we introduced in the previous lessons are more
known and familiar, we will mostly use them.
Because the data types are defined as classes, they are equipped with methods. One of
the methods that each one of them has is called ToString. As its name implies, it is used
to convert a value to a string.
C# Language Accessories
In Lesson 1, we saw that, to see the result of an application, you must execute it. To
make this possible,, Microsoft Visual C# ships with an internal program called a compiler.
A compiler is a computer program made of internal other sub-programs. One of the
sub-programs, in fact probably the first, of a compiler is called a parser. A parser "scans"
a file that contains (part of) the program. It checks for syntax, keywords, unknown words,
and some other routines. If the parser finds a problem, which could be anything, either it
stops or it continues making a list of the mistakes it found. Then it displays this list to you
to fix. Sometimes it would point to the exact line where the/a problem was found.
Sometimes it would point to the line where the problem showed its impact although the
problem may be found somewhere else. With experience, you will know how to fix the
programs or troubleshoot these problems. In this ebook, we will address as many issues
as possible.
If the parser doesn't find any problem, or after you have fixed the problems, it (the
parser) passes its result(s) to the compiler. The compiler calls another program called a
The compiler that ships with the C# version we will use, that is, the compiler of the
Microsoft .NET Framework is a program called csc. Like most other programs, it has the
extension .exe. This csc name is not standard. This means that another C# compiler may
have another name; csc.exe is just the name of the compiler we will use.
The csc compiler is freely available if you download the .NET Framework from the
Microsoft web site.
In this book, we will create our program using Microsoft Visual C# but if you didn't have it,
you would still be able to create and execute applications. To do this, at the Command
Prompt, you would type csc, followed by the name of the file that contains the code with
its extension. An example would be:
csc Filename.cs
When you do this, an executable with the same name as the file is created. If you want,
you can ask the compiler to produce an executable using the name of your choice. To do
this, you would compile the project using the following formula:
csc /out:NameOfExecutate.exe Filename.cs
The NameOfExecutate factor in our formula represents the name you want the executable
to have. If the name you want is in one word, you can just type it. If you want a name
made of various words, you can include those words in double-quotes
Unsafe Code
When C# was invented, one of its biggest goals was to avoid some of the difficulties of
C/C++. Among them was the use of pointers. C/C++ uses pointers to refer to the area in
memory where a value is located. C# highly avoids pointers and takes over memory
management as opposed to letting the programmer take care of that aspect of an
application. You can still use pointers in C# in extreme cases when you judge them
necessary.
Because the C# compiler is in charge of managing the memory used by the values of an
application, pointers are said to be unsafe. If you want to use a pointer in your
application, you must precede the name of every method that uses unsafe code with the
unsafe keyword. Here is an example:
class Exercise
{
unsafe static void Main()
{
int Length = 224;
int *Len = &Length;
Console.Write("Length ");
Console.WriteLine(Length);
Console.Write("Length ");
Console.WriteLine(*Len);
Console.WriteLine();
Length = 804;
Console.Write("Length ");
Console.WriteLine(Length);
Console.Write("Length ");
Console.WriteLine(*Len);
}
}
To compile the application, you must indicate that you are using unsafe code. To do that,
use the /unsafe modifier. Here is an example:
csc /unsafe Exercise.cs
To apply this option in Microsoft Visual C#, on the main menu, you can click Project ->
Project Properties... In the Build section, click the Allow Unsafe Code check box:
Microsoft Visual C# provides various techniques to assist you with code writing and
management. The characteristics include color-coded words, intuitive indentation,
delimitation of sections of code, etc. Consider the following contents of the Code Editor
based on what we have reviewed so far:
Notice that there are - buttons on the left side of some lines of code. These allow you to
collapse a section of code if you think you don't need to see it. To do this, you can click
the - button. If you click that - button, it changes into a + button. Here is an example:
Besides, or instead of, the sections of code created by the Code Editor, if you want, you
can create your own sections. To do this, start the section with
#region Whatever
When and where you start, the #region expression is required. On the right side of this
expression, you can type anything you want on the line. To end the section, type
#endregion, followed by anything you want. Consider the following example:
using System;
class House
{
void Create()
{
}
}
class Student
{
void Register()
{
}
}
#endregion We can just stop it here
class Program
{
static void Main()
{
}
}
You don't have to type anything on the right side of #endregion. After creating the
region, the Code Editor would display a - button to the left side of #region with a line
from there to the left of #endregion:
This then allows you to expand and collapse that section at will:
Data Reading
Introduction
In previous lessons, we saw that the Console class allows using the Write() and the
WriteLine() methods to display things on the screen. While the Console.Write()
method is used to display something on the screen, the Console class provides the
Read() method to get a value from the user. To use it, the name of a variable can be
assigned to it. The syntax used is:
VariableName = Console.Read();
This simply means that, when the user types something and presses Enter, what the user
had typed would be given (the word is assigned) to the variable specified on the left side
of the assignment operator.
Read() doesn't always have to assign its value to a variable. For example, it can be used
on its own line, which simply means that the user is expected to type something but the
value typed by the user would not be used for any significant purpose. For example some
versions of C# (even including Microsoft's C# and Borland C#Builder) would display the
DOS window briefly and disappear. You can use the Read() function to wait for the user
to press any key in order to close the DOS window.
Besides Read(), the Console class also provides the ReadLine() method. Like the
WriteLine() member function, after performing its assignment, the ReadLine() method
sends the caret to the next line. Otherwise, it plays the same role as the Read() function.
In most assignments of your programs, you will not know the value of a string when
writing your application. For example, you may want the user to provide such a string. To
request a string (or any of the variables we will see in this lesson), you can call the
using System;
namespace GeorgetownCleaningServices4
{
class Program
{
static void Main(string[] args)
{
string CustomerName, HomePhone;
Console.WriteLine();
// Display the receipt
Console.WriteLine("====================================");
Console.WriteLine("-/- Georgetown Cleaning Services -/-");
Console.WriteLine("====================================");
Console.Write("Customer: ");
Console.WriteLine(CustomerName);
Console.Write("Home Phone: ");
Console.WriteLine(HomePhone);
Console.WriteLine("====================================\n");
}
}
}
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: James Watson
Home Phone: (410) 493-2005
====================================
Number Request
In C#, everything the user types is a string and the compiler would hardly analyze it
without your explicit asking it to do so. Therefore, if you want to get a number from the
user, first request a string. Here is an example:
using System;
strNumber = Console.ReadLine();
}
}
After getting the string, you must convert it to a number. To perform this conversion, each
data type of the .NET Framework provides a mechanism called Parse. To use Parse(),
type the data type, followed by a period, followed by Parse, and followed by parentheses.
In the parentheses of Parse, type the string that you requested from the user. Here is an
example:
using System;
strNumber = Console.ReadLine();
Number = int.Parse(strNumber);
}
}
Number = int.Parse(Console.ReadLine());
return 0;
}
}
1. To retrieve various numbers from the user, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GeorgetownCleaningServices4
{
class Program
{
static void Main(string[] args)
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Genevieve Alton
Home Phone: (202) 974-8244
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 8 0.95 7.60
Pants 2 2.95 5.90
Dresses 3 4.55 13.65
------------------------------------
Total Order: 27.15
Tax Rate: 5.7500%
Tax Amount: 1.561125
Net Price: 28.711125
------------------------------------
Amount Tended: 30
Difference: 1.288875
====================================
namespace ValueRequests
{
class Exercise
{
static void Main()
{
string strDateHired;
strDateHired = Console.ReadLine();
}
}
}
After the user has entered the string you can then convert it to a DateTime value. Just
like any value you request from the user, a date or time value that the user types must be
valid, otherwise, the program would produce an error. Because dates and times follow
some rules for their formats, you should strive to let the user know how you expect the
value to be entered.
By default, if you request only a date from the user and the user enters a valid date, the
compiler would add the midnight value to the date. If you request only the time from the
user and the user enters a valid time, the compiler would add the current date to the
value. Later on, we will learn how to isolate either only the date or only the time.
1. To deal with new dates and times, change the program as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GeorgetownCleaningServices4
{
class OrderProcessing
{
static void Main()
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
3. Return to Notepad
Introduction
1. The first part of the string provided to Write() or WriteLine() is the complete
string that would display to the user. This first string itself can be made of different
sections:
You can put the placeholder anywhere inside of the string. The first
placeholder must have number 0. The second must have number 1, etc.
With this technique, you can create the string anyway you like and use the
placeholders anywhere inside of the string
2. The second part of the string provided to Write() or WriteLine() is the value
that you want to display. It can be one value if you used only one placeholder with
0 in the first string. If you used different placeholders, you can then provide a
different value for each one of them in this second part, separating the values with
a comma
Console.WriteLine();
}
}
As mentioned already, the numeric value typed in the curly brackets of the first part is an
ordered number. If you want to display more than one value, provide each incremental
value in its curly brackets. The syntax used is:
Write("To Display {0} {1} {2} {n}", First, Second, Third, nth);
You can use the sections between a closing curly bracket and an opening curly bracket to
create a meaningful sentence.
namespace GeorgetownCleaningServices4
{
class OrderProcessing
{
static void Main()
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
Conversion To String
We mentioned earlier that everything the user types using the keyboard is primarily a
string and it's your job to convert it to the appropriate type. In reverse, if you have a
value that is not a string, you can easily convert it to a string. To support this, each .NET
Framework data type provides a mechanism called ToString. Normally, in C#, as we
mentioned with boxing, and as we have done so far, this conversion is automatically or
transparently done by the compiler. In some cases, you will need to perform the
conversion yourself.
To convert a value of a primitive data type to a string, type the name of the variable,
followed by a period, followed by ToString(). Here is an example:
using System;
Console.WriteLine();
}
C# 3.0 Practical Learning 121
}
namespace GeorgetownCleaningServices4
{
class OrderProcessing
{
static void Main()
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
. . . No Change
Console.WriteLine("------------------------------------");
Console.WriteLine("Shirts {0} {1} {2}",
NumberOfShirts.ToString(),
PriceOneShirt,
SubTotalShirts.ToString());
Console.WriteLine("Pants {0} {1} {2}",
NumberOfPants, PriceAPairOfPants,
SubTotalPants);
Console.WriteLine("Dresses {0} {1} {2}",
NumberOfDresses, PriceOneDress,
SubTotalDresses);
Console.WriteLine("------------------------------------");
Console.WriteLine("Total Order: {0}", TotalOrder);
Console.WriteLine("Tax Rate: {0}%", TaxRate * 100);
Console.WriteLine("Tax Amount: {0}",
TaxAmount.ToString());
Console.WriteLine("Net Price: {0}", SalesTotal);
Console.WriteLine("------------------------------------");
Console.WriteLine("Amount Tended: {0}", AmountTended);
Console.WriteLine("Difference: {0}", Difference);
Console.WriteLine("====================================");
}
}
}
Number Formatting
The System namespace provides a specific letter that you can use in the Write() or
WriteLine()'s placeholder for each category of data to display. To format a value, in the
placeholder of the variable or value, after the number, type a colon and one of the
appropriate letters from the following table. If you are using ToString(), then, in the
parentheses of ToString(), you can include a specific letter or combination inside of
double-quotes. The letters and their meanings are:
c C Currency values
d D Decimal numbers
n N Natural numbers
r R Roundtrip formatting
x X Hexadecimal formatting
p P Percentages
Console.WriteLine();
}
}
As you may have noticed, if you leave the parentheses of ToString() empty, the
compiler would use a default formatting to display the value.
As opposed to calling ToString(), you can use the above letters in the curly brackets of
the first part of Write() or WriteLine(). In this case, after the number in the curly
brackets, type the colon operator followed by the letter.
namespace GeorgetownCleaningServices4
{
class OrderProcessing
{
static void Main()
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Gretchen McCormack
Home Phone: (410) 739-2884
Date & Time: 4/9/2001 10:25:00 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 5 $0.95 $4.75
Pants 12 $2.95 $35.40
Dresses 8 $4.55 $36.40
------------------------------------
Total Order: $76.55
Tax Rate: 5.75 %
Tax Amount: $4.40
Net Price: 80.95
------------------------------------
Amount Tended: $100.00
Difference: $19.05
C# 3.0 Practical Learning 126
====================================
Line Formatting
In the above programs, to display a line of text, we easily used Write() or WriteLine().
To position text of different lengths one above the other, we had to "corrupt" a string by
including extra-empty spaces. Such a technique is uncertain and less professional.
Fortunately, you can highly format how a string or a line of text should display. The .NET
Framework provides mechanisms to control the amount of space used to display a string
of text and how to align that string on its line.
To specify the amount of space used to display a string, you can use its placeholder in
Write() or WriteLine(). To do this, in the placeholder, type the 0 or the incrementing
number of the placer and its formatting character if necessary and if any. Then, type a
comma followed by the number of characters equivalent to the desired width. Here are
examples:
using System;
Console.WriteLine();
}
}
The sign you provide for the width is very important. If it is positive, the line of text is
aligned to the right. This should be your preferred alignment for numeric values. If the
number is negative, then the text is aligned to the left.
As mentioned earlier, when the user enters a date value for a DateTime variable, the
compiler adds a time part to the value. Fortunately, if you want to consider only the date
or only the time part, you can specify this to the compiler. To support this, the DateTime
data type provides a series of letters you can use to format how its value should be
displayed to the user. The character is entered in the placeholder of the DateTime
variable after the 0 or the incremental numeric value.
C# 3.0 Practical Learning 127
Practical Learning: Controlling Date/Time Formatting
namespace GeorgetownCleaningServices4
{
class OrderProcessing
{
static void Main()
{
// Price of items
const double PriceOneShirt = 0.95;
const double PriceAPairOfPants = 2.95;
const double PriceOneDress = 4.55;
const double TaxRate = 0.0575; // 5.75%
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Antoinette Calhoun
Home Phone: (703) 797-1135
Order Date: Friday, April 12, 2002
Order Time: 2:12 PM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 5 $0.95 $4.75
Pants 2 $2.95 $5.90
Dresses 1 $4.55 $4.55
------------------------------------
Total Order: $15.20
Tax Rate: 5.75 %
Tax Amount: $0.87
Net Price: $16.07
------------------------------------
Amount Tended: $20.00
Difference: $3.93
====================================
Introduction
In the body of a method, you can declare one or more variables that would be used only
by the method. A variable declared in the body of a method is referred to as a local
variable. The variable cannot be accessed outside of the method it belongs to. After
declaring a local variable, it is made available to the method and you can use it as you see
fit, for example, you can assign it a value prior to using it.
2. To create a new class, on the main menu, click Project -> Add Class...
4. To declare and use local variables of a method, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry1
{
public class Cylinder
{
public void Process()
{
double Radius, Height;
double BaseArea, LateralArea, TotalArea;
double Volume;
Console.WriteLine("\nCylinder Characteristics");
Console.WriteLine("Radius: {0}", Radius);
Console.WriteLine("Height: {0}", Height);
Console.WriteLine("Base: {0:F}", BaseArea);
Console.WriteLine("Lateral: {0:F}", LateralArea);
Console.WriteLine("Total: {0:F}", TotalArea);
Console.WriteLine("Volume: {0:F}", Volume);
}
}
}
namespace Geometry1
{
public class Program
{
static void Main()
{
Cylinder cyl = new Cylinder();
cyl.Process();
Console.WriteLine();
}
}
}
Cylinder Characteristics
Radius: 38.64
Height: 22.48
Base: 4690.55
Lateral: 5457.75
Total: 14838.85
Volume: 105443.65
If a method has carried an assignment and must make its result available to other
methods or other classes, the method must return a value and cannot be void. To
declare a method that returns a value, provide its return type to the left of its name. Here
is an example:
using System;
class Exercise
{
{
}
After a method has performed its assignment, it must clearly demonstrate that it is
returning a value. To do this, you use the return keyword followed by the value that the
method is returning. The value returned must be of the same type specified as the return
type of the method. Here is an example:
using System;
class Exercise
{
static double Operation()
{
return 24.55;
}
A method can also return an expression, provided the expression produces a value that is
conform to the return type. Here is an example:
using System;
class Exercise
{
static double Operation()
{
return 24.55 * 4.16;
}
class Exercise
{
static double Operation()
{
return 24.55;
}
In the same way, a method that returns a value can be assigned to a variable of the same
type.
namespace Geometry1
{
class Cylinder
{
public double GetRadius()
{
double rad;
Console.Write("Radius: ");
rad = double.Parse(Console.ReadLine());
return rad;
}
Console.Write("Height: ");
h = double.Parse(Console.ReadLine());
return h;
C# 3.0 Practical Learning 134
}
Console.WriteLine("\nCylinder Characteristics");
Console.WriteLine("Radius: {0}", Radius);
Console.WriteLine("Height: {0}", Height);
Console.WriteLine("Base: {0:F}", BaseArea);
Console.WriteLine("Lateral: {0:F}", LateralArea);
Console.WriteLine("Total: {0:F}", TotalArea);
Console.WriteLine("Volume: {0:F}", Volume);
}
}
}
Cylinder Characteristics
Radius: 52.08
Height: 36.44
Base: 8521.02
Lateral: 11924.20
Total: 28966.25
Volume: 310506.14
So far, we have used the Main() method as it is defined by default when you create an
application using using New Project dialog box. This default implementation of the Main()
method is of type void. Another way to implement the Main() method is to make it
return an integer. The rule is the same as for any method of type int. The Main() method
can return any type of integer as long as it is a valid integer. Here is an example:
using System;
class Exercise
{
static char HaveCharacter()
C# 3.0 Practical Learning 135
{
return 'G';
}
return 244006;
}
}
Methods' Arguments
Introduction
A method performs an assignment that completes the operations of a class. The methods
we used in the previous sections relied on local variables to exchange information with
other sections of the program. Sometimes, a method would need one or more values in
order to carry its assignment. The particularity of such a value or such values is that
another method that calls this one must supply the needed value(s). When a method
needs a value to complete its assignment, such a value is called an argument.
Like a variable, an argument is represented by its type of value. For example, one method
may need a character while another would need a string. Yet another method may require
a decimal number. This means that the method or class that calls a method is responsible
for supplying the right value, even though a method may have an internal mechanism of
checking the validity of such a value.
The value supplied to a method is typed in the parentheses of the method and it's called
an argument. In order to declare a method that takes an argument, you must specify its
name and the argument between its parentheses. Because a method must specify the
type of value it would need, the argument is represented by its data type and a name.
Suppose you want to define a method that displays the side length of a square. Since you
would have to supply the length, you can define such a method as follows:
using System;
In the body of the method, you may or may not use the value of the argument.
Otherwise, you can manipulate the supplied value as you see fit. In this example, you can
display the value of the argument as follows:
using System;
When calling a method that takes an argument, you must supply a value for the
argument; otherwise you would receive an error. Also, you should/must supply the right
value; otherwise, the method may not work as expected and it may produce an unreliable
result. Here is an example:
using System;
return 0;
}
}
As mentioned already, a method that takes an argument can also declare its own local
variable(s). A method can take more than one argument. When defining such a method,
provide each argument with its data type and a name. The arguments are separated by a
comma.
namespace Geometry1
{
public class Cylinder
{
public double GetRadius()
{
double rad;
Console.Write("Radius: ");
rad = double.Parse(Console.ReadLine());
return rad;
}
Console.Write("Height: ");
h = double.Parse(Console.ReadLine());
return h;
}
BaseArea = CalculateBaseArea(Radius);
C# 3.0 Practical Learning 138
LateralArea = CalculateLateralArea(Radius, Height);
TotalArea = CalculateTotalArea(Radius, Height);
Volume = CalculateVolume(Radius, Height);
Console.WriteLine("\nCylinder Characteristics");
Console.WriteLine("Radius: {0}", Radius);
Console.WriteLine("Height: {0}", Height);
Console.WriteLine("Base: {0:F}", BaseArea);
Console.WriteLine("Lateral: {0:F}", LateralArea);
Console.WriteLine("Total: {0:F}", TotalArea);
Console.WriteLine("Volume: {0:F}", Volume);
}
}
}
Cylinder Characteristics
Radius: 35.96
Height: 30.28
Base: 4062.46
Lateral: 6841.56
Total: 14966.49
Volume: 123011.33
When calling a methods that takes one or more arguments, we made sure we provided
the necessary value. This is because an argument is always required and the calling
method must provide a valid value when calling such a method.
Rate = 15.58;
Hours = 26.00;
Earnings(Hours, Rate);
Console.Write("\n");
return 0;
}
}
Weekly Hours = 26
Salary = 15.58
Weekly Salary = 405.08
Weekly Hours = 26
Salary = 15.58
C# 3.0 Practical Learning 140
Weekly Salary = 405.08
Notice that the weekly hours and salary values are the same before and after calling the
Earnings() method.
When you declare a variable in a program, the compiler reserves an amount of space for
that variable. If you need to use that variable somewhere in your program, you call it and
make use of its value. There are two major issues related to a variable: its value and its
location in the memory. The location of a variable in memory is referred to as its address.
If you supply the argument using its name, the compiler only makes a copy of the
argument’s value and gives it to the calling method. Although the calling method receives
the argument’s value and can use it in any way, it cannot (permanently) alter it. C# allows
a calling method to modify the value of a passed argument if you find it necessary. If you
want the calling method to modify the value of a supplied argument and return the
modified value, you should pass the argument using its reference.
To pass an argument as a reference, when defining and when calling the method, precede
the argument's data type with the ref keyword. You can pass 0, one, or more arguments
as reference in the program or pass all arguments as reference. The decision as to which
argument(s) should be passed by value or by reference is based on whether or not you
want the called method to modify the argument and permanently change its value.
Another option consists of passing an argument using the out keyword. Here is an
example:
using System;
class Exercise
{
static void Initializer(out double n)
{
n = 128.44;
}
If you pass an argument with out, any modification made on the argument would be kept
when the method ends. When calling a method that takes an out argument, precede the
argument with the out keyword. Here is an example:
using System;
class Exercise
{
static void Initializer(out double n)
{
n = 128.44;
namespace Geometry1
{
class Cylinder
{
public void GetRadius(ref double rad)
{
Console.Write("Radius: ");
rad = double.Parse(Console.ReadLine());
}
BaseArea = CalculateBaseArea(Radius);
LateralArea = CalculateLateralArea(Radius, Height);
TotalArea = CalculateTotalArea(Radius, Height);
Volume = CalculateVolume(Radius, Height);
Console.WriteLine("\nCylinder Characteristics");
Console.WriteLine("Radius: {0}", Radius);
Console.WriteLine("Height: {0}", Height);
Console.WriteLine("Base: {0:F}", BaseArea);
Console.WriteLine("Lateral: {0:F}", LateralArea);
Console.WriteLine("Total: {0:F}", TotalArea);
Console.WriteLine("Volume: {0:F}", Volume);
}
}
}
Cylinder Characteristics
Radius: 24.55
Height: 20.85
Base: 1893.45
Lateral: 3216.16
Total: 7003.05
Volume: 39478.34
Method Overloading
A typical program involves a great deal of names that represent variables and methods of
various kinds. The compiler does not allow two variables to have the same name in the
same method. Although two methods should have unique names in the same program, a
class can have different methods with the same name if you follow some rules. The ability
to have various methods with the same name in the same program is referred to as
C# 3.0 Practical Learning 143
method overloading. To perform overloading, the methods must have different numbers
or different type(s) of arguments.
The moment of inertia is the ability of a beam to resist bending. It is calculated with
regard to the cross section of the beam. Because it depends on the type of section of the
beam, its calculation also depends on the type of section of the beam. In this exercise, we
will review different formulas used to calculate the moment of inertia. Since this exercise
is for demonstration purposes, you do not need to be a Science Engineering major to
understand it.
Console.WriteLine();
return 0;
}
}
5. A circle, and thus a semi-circle, requires only a radius. Since the other version of
the MomentOfInertia() function requires two arguments, we can overload it by
providing only one argument, the radius.
To overload the above MomentOfInertia() method, type the following in the file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// Semi-Circle
static double MomentOfInertia(double R)
{
const double PI = 3.14159;
return R * R * R * R * PI/ 8;
}
Console.WriteLine();
return 0;
}
}
9. As you can see, the rectangle and the triangle are using the same dimension types.
This means that we can provide only the same kinds of arguments, the base and
the height, to calculate the moment of inertia. This also means that the compiler
will not allow us to write two methods that have the same name, the same number
of arguments, and the same types of arguments because that would violate the
rule of function overloading.
10.In order to overload the MomentOfInertia() function, we will add an argument that
will never be used; this argument will serve only as a “witness” to set the difference
C# 3.0 Practical Learning 146
between both versions of the function. This “witness” argument can be anything:
an integer, a character, a string, a float, etc. For our example, we will make it a
simple integer. To use the version applied to the triangle, we will provide this
argument to overload the MomentOfInertia() function. When called with only two
arguments, the rectangle version will apply.
Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// Semi-Circle
static double MomentOfInertia(double R)
{
const double PI = 3.14159;
return R * R * R * R * PI/ 8;
}
// Triangle
static double MomentOfInertia(double b, double h, int i)
{
return b * h * h * h / 12;
}
Console.WriteLine(
"Rectangle - Moment of inertia with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height));
Console.WriteLine(
"\nTriangle - Moment of inertia with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height, 1));
Method Initializer
Imagine you are writing a program for a business that sells flowers:
Flower
If you declare a variable of a class in your program, when the program comes up, the
compiler reserves enough memory space for each member of the class. The memory
space reserved for each member variable is filled with an initial value based on its type.
For a string object, the space would be left empty. For an integer type, the space would
be filled with 0. A better way to take care of this type is to provide a value whose role
would be to initialize the member variables with the values of your choice. A method that
initializes an object can return any value but it is preferable to be of type void because its
primary purpose is to reset the values. Since this method would give a starting value to all
member variables that need to be initialized, it should have an equivalent argument for
each of the member variables that it would initialize. Here is an example:
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public double UnitPrice;
public void Initializer(int tp, int clr, char arng, double price)
{
}
}
The method initializer does not have to initialize all members of the class. For example,
the previous execution of the program shows that the member variables that are of type
public void Initializer(int tp, int clr, char arng, double price)
{
Type = tp;
Color = clr;
Arrangement = arng;
UnitPrice = price;
}
}
You can call a method initializer after declaring the instance of the class to give it initial
values. Here is an example:
using System;
Using a method initializer, after initializing the object, you can use the values it holds as
you see fit.
Default Constructor
A constructor is a special method that is created when the object comes to life. This
particular method holds the same name as the class and it initializes the object whenever
that object is created. When you create a class, if you don't declare a constructor, the
compiler creates one for you; this is useful because it lets all other objects of the program
know that the object exists. This compiler-created constructor is called the default
constructor. If you want, you can create your own constructor.
To create a constructor, declare a method that holds the same name as the class.
Remember that the method must not return any value.
Here is an example:
namespace FlowerShop
{
public class Flower
{
Flower()
{
}
}
}
When you declare an instance of the class, whether you use that object or not, a
constructor for the object is created. When an instance of a class has been declared, the
default constructor is called, whether the object is used or not. This is illustrated in the
following program:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Console.WriteLine("New Flower Order");
}
}
As you can see, even though the flr variable was not used, just its declaration was enough
to signal it. You might find it sometimes convenient to create your own constructor
because, whether you create an empty constructor or not, this does not negatively impact
your program.
To implement a default constructor, you can just initialize the desired members of the
class. For a member variable of a numeric type, you can just assign the desired constant
to each. If the variable is a character, assign a single-quoted symbol to it. If the variable is
a string, then assign a double-quoted value to the variable. Here are examples:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = 1;
Color = 1;
Arrangement = 'V';
UnitPrice = 0M;
}
C# 3.0 Practical Learning 152
}
Constructor Overloading
The default constructor is the favorite place to provide default values to the members of a
class. Besides the default constructor, you can add as many constructors as you judge
necessary. This feature of C# allows you to create various constructors for different
reasons. This also means that the methods or constructors of a class can be overloaded.
One of the rules of method overloading consists of having methods with different types of
arguments. The most basic constructor you would create can use a single argument.
When implementing a constructor that takes one argument, you should initialize the
member that corresponds to the unique argument and initialize the other members with
default values. Here is an example:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = 1;
Color = 1;
Arrangement = 'V';
UnitPrice = 0M;
}
If you create a class with only one constructor as in the current example, when declaring
an instance of the class, you must use that constructor: you cannot use the default
constructor that doesn't take an argument. When declaring the variable, initialize it with a
constructor with parentheses and provide the value(s) in the parentheses of the
constructor. Here is an example:
using System;
namespace FlowerShop
{
public class Flower
{
public string Type;
public string Color;
public string Arrangement;
public double UnitPrice;
public Flower()
{
Type = "";
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95D;
}
In the same way, you can create different constructors for different initializations,
although it would not be realistic to create a different constructor for each variable. If you
create different constructors with different arguments to initialize (remember the rules of
method overloading), when declaring the classes, make sure you initialize each instance
with the right number of arguments; otherwise, the compiler would complain.
If you create a class with only one constructor and that constructor has at least one
argument, the default constructor would not be available anymore. If you want to access
a default constructor of an object, you have two alternatives:
If you don't create any constructor at all on a class, the default constructor would
always be available whenever you invoke that class
If you create at least one constructor on a class and supply at least one argument
to that constructor, you must explicitly create a default constructor for your class.
To create a destructor, type ~ followed by the name of the class. Here is an example:
public Flower()
{
Type = "";
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95M;
}
~Flower()
{
}
}
}
Classes Combinations
Class Nesting
A class can be created inside of another class. A class created inside of another is referred
to as nested. To nest a class, simply create it as you would any other. Here is an example
of a class called Inside that is nested in a class called Outside:
public class Outside
{
public class Inside
{
}
}
In the same way, you can nest as many classes as you wish in another class and you can
nest as many classes inside of other nested classes if you judge it necessary. Just as you
would manage any other class so can you exercise control on a nested class. For
example, you can declare all necessary fields, properties, or methods in the nested class
or in the nesting class. When you create one class inside of another, there is no special
programmatic relationship between both classes: just because a class is nested does not
mean that the nested class has immediate access to the members of the nesting class.
They are two different classes and they can be used separately as you judge it necessary.
The name of a nested class is not "visible" outside of the nesting class. To access a nested
class outside of the nesting class, you must qualify the name of the nested class anywhere
you want to use it. For example, if you want to declare an Inside variable somewhere in
the program but outside of Outside, you must qualify its name. Here is an example:
using System;
return 0;
}
}
public Inside()
{
Console.WriteLine(" -= Insider =-");
InMessage = "Sitting inside while it's raining";
}
public Outside()
{
Console.WriteLine(" =- The Parent -=");
}
Recto.Display();
return 0;
}
}
In the same way, if you want to access the nesting class in the nested class, you can go
through the static members of the nesting class. To do this, you can declare static all
members of the nesting class that you want to access in the nested class. Here is an
example:
using System;
public Inside()
{
Console.WriteLine(" -= Insider =-");
InMessage = "Sitting inside while it's raining";
}
public Outside()
{
Console.WriteLine(" =- The Parent -=");
OutMessage = "Standing outside! It's cold and raining!!";
}
Recto.Display();
Console.WriteLine();
Ins.FieldFromOutside();
return 0;
}
}
Instead of static members, if you want to access members of a nested class in the nesting
class, you can first declare a variable of the nested class in the nesting class. In the same
way, if you want to access members of a nesting class in the nested class, you can first
declare a variable of the nesting class in the nested class. Here is an example:
using System;
Ins.Show();
Recto.Display();
return 0;
}
}
A Class as a Field
Just like any of the variables we have used so far, you can make a class or a structure a
member variable of another class. To use a class in your own class, of course you must
have that class. You can use one of the classes already available in C# or you can first
create your own class. Here is an example of a class:
public class Point
{
internal short x;
internal short y;
}
A field is a member variable created from another class instead of a primitive type. To use
one class as a member variable of another class, simply declare its variable as you would
proceed with any of the member variables we have declared so far. Here is an example:
public class Point
{
After a class has been declared as a member variable of another class, it can be used
regularly. Because the member is a class, declared as a reference, there are some rules
you must follow to use it. After declaring the member variable, you must make sure you
have allocated memory for it. You must also make sure that the variable is initialized
appropriately before it can be used; otherwise you would receive an error when compiling
the program.
2. To create a new class, in the Solution Explorer, right-click the name of the project,
position the mouse on Add and click Class...
namespace ElectronicStore1
{
public class StoreItem
{
private long nbr;
private char cat;
private string mk;
private string mdl;
private double price;
namespace ElectronicStore1
{
class Program
{
static void Main()
{
string strTitle1 = "=-= Nearson Electonics =-=\n";
string strTitle2 = "******* Store Items ******";
Console.WriteLine();
}
}
}
6. Save all
C# 3.0 Practical Learning 163
Returning a Class or Passing a Class
Like a value from a regular type, you can return a class value from a method of a class. To
do this, you can first declare the method and specify the class as the return type. Here is
an example:
public class Point
{
internal short x;
internal short y;
}
After implementing the method, you must return a value that is conform to the class,
otherwise you would receive an error when compiling the application. You can proceed by
declaring a variable of the class in the body of the method, initializing the variable, and
then returning it. Here is an example:
public class Point
{
internal short x;
internal short y;
}
Once a method has returned a value of a class, the value can be used as normally as
possible.
Once a class has been created, it can be used like any other variable. For example, its
variable can be passed as argument to a method of another class. When a class is passed
as argument, its public members are available to the method that uses it. As done for the
arguments of primitive types, you can pass more than one class as argument to a method.
Here are different examples:
using System;
namespace Geometry
{
public class Point
{
internal short x;
internal short y;
}
Console.WriteLine("Start Point");
C# 3.0 Practical Learning 165
coord.Start = coord.GetThePoint();
Console.WriteLine("End Point");
coord.End = coord.GetThePoint();
return coord;
}
Console.WriteLine();
Show(coord);
return 0;
}
}
}
Coordinate System
Starting Point: P(-2, 2)
Ending Point: Q(3, -6)
Distance Between Both Points: 9.43
Press any key to continue . . .
Because classes are always used as references, when passing a class as argument, it is
implied to be passed by reference. To reinforce this, you can type the ref keyword to the
left of the argument. Here is an example:
using System;
namespace ConsoleApplication1
{
public class Point
{
internal short x;
internal short y;
}
Console.WriteLine("Start Point");
coord.Start = coord.GetThePoint();
Console.WriteLine("End Point");
coord.End = coord.GetThePoint();
return coord;
}
Console.WriteLine();
Show(coord);
return 0;
}
}
}
namespace ElectronicStore1
{
public class SaleItem
{
double DiscountAmount;
double NetPrice;
int Quantity;
double SaleTotal;
saleItem.SetItemNumber(itemNumber);
saleItem.SetCategory(category);
saleItem.SetMake(make);
saleItem.SetModel(model);
saleItem.SetUnitPrice(price);
return saleItem;
}
Console.WriteLine(strTitle1);
Console.WriteLine(strTitle2);
item = sale.Create();
sale.ShowSaleItem(item);
Console.WriteLine();
}
}
}
An instance of a class can be passed as an argument to one of its own methods (if you
have programmed in C++, an example of this implementation is the copy constructor;
although you can legitimately create a copy constructor in C#, it does not have the exact
same concept as in C++, probably because C# has the Equals() method, which is
actually a concept of the .NET Framework). To do this, you primarily pass the argument as
if it were any class. Here is an example:
public class Point
{
internal int x;
internal int y;
Then, in the body of the method, do whatever you want. You can, or you may not, use
the argument. Still, if you decide to use the argument, know that all of the other members
of the class are available through the argument. Probably the simplest way to use the
argument is the assign each of of its values to the equivalent member of the class. Here is
an example:
public class Point
{
internal int x;
internal int y;
When calling the method, make sure you pass an instance of the class to it. You can first
create and define the class, then pass it. Here is an example:
using System;
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
Instead of first declaring a variable of the class and initializing it, you can create an
instance of the class in the parentheses of the calling method. To do this, you may need a
constructor that can specify the values of the fields of the class so the argument can be
rightfully initialized. Here is an example:
using System;
public Point()
{
}
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
Instead of a formal method, you can use a constructor of the class to pass an instance of
the same class. Then, in the constructor, use the argument as you see fit, knowing that all
the members of the class are available. Here is an example:
public class Point
{
internal int x;
internal int y;
public Point()
{
}
Obviously the purpose of passing a class to one of its own methods is not to find its
equivalent. The C# language (actually the .NET Framework) can also take care of that
(through the Equals() built-in method). Instead, you can create a method that takes an
instance of the same class but modifies that instance. For example, for our Point class, we
may want to create a new point that is distanced by one unit from the current Point
object. Here is an example of doing that:
using System;
public Point()
{
}
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
You can create a method in a class that returns an instance of the class. To start, on the
left side of the method, enter the name of the class. Here is an example:
public class Point
{
public Point MethodName()
{
}
}
There are various ways you can deal with the method. If you want to return a new value
of the class, you can declare an instance of the class, initialize it, and then return it. Here
is an example:
using System;
public Point()
{
}
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
Alternatively, you can declare an instance of the class, use the current values of the class
combined with the those of the instance to get new values, and then return the instance.
Here is an example:
using System;
public Point()
{
}
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
Remember that, to call the method, if it is not static, you will need to declare an instance
of the class from where you are calling the method. The second type of implementation
consists of modifying the instance of the class that is calling the method. For example, you
can add values to its fields or you can perform any other operation you want on the
members of the calling instance. is an example:
using System;
public Point()
{
}
pt.x = 4;
pt.y = 6;
ShowPoint(pt);
return 0;
}
}
As we have learned now, you can create a method that takes an argument that is the
same type as its parent class. In the method, you can access any member of the class,
including calling the other methods of the class.
Boolean Variables
Introduction
When interacting with a computer, a user submits values to a running application. Some
of these values are valid. Some other values must be rejected or changed. To take care of
these, the values must be checked, examined, re-examined, etc. The validity of a value is
checked against its type. For example, a number can be checked as being equal to
another. A condition can be checked as being true. A measure can be checked as to
whether it is higher than a certain threshold.
To perform the necessary validations of values, the C# language provides some symbols,
referred to as Boolean operators.
3. To create a new class, on the main menu, click Project -> Add Class...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FlowerShop1
{
public class Flower
{
public int Type;
public Flower()
{
Type = 0;
Color = 0;
Arrangement = 'B';
UnitPrice = 0.00M;
}
6. To create a new class, in the Solution Explorer, right-click the project name,
position the mouse on Add and click Class...
namespace FlowerShop1
{
public class OrderProcessing
{
public OrderProcessing()
{
FlowerOrder = new Flower();
}
namespace FlowerShop1
{
public class Program
{
private static OrderProcessing CreateFlowerOrder()
{
OrderProcessing order = new OrderProcessing();
int type, color, qty;
char arrangement;
decimal price;
Console.WriteLine("=======================");
Console.WriteLine("==-=-=Flower Shop=-=-==");
Console.WriteLine("-----------------------");
return order;
}
ShowFlowerOrder(flower);
Console.WriteLine();
}
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: 4
Flower Color: 6
Arrangement: V
Price: $37.95
Quantity: 2
Total Price: $75.90
=======================
A variable is referred to as Boolean if it can hold a value that is either true or false. To
declare a Boolean variable, you can use either the var or the bool keyword. Here is an
example:
using System;
return 0;
}
}
Alternatively, you can declare a Boolean variable using the Boolean data type. The
Boolean data type is part of the System namespace. Here is an example:
using System;
return 0
}
After the variable has been declared, you must initialize it with a true or a false value.
In fact, if you declare it as var, you must initialize it. Here is an example:
using System;
return 0;
}
}
To display the value of a Boolean variable on the console, you can type its name in the
parentheses of the Write() or the WriteLine() methods of the Console class. Here is
an example:
using System;
At any time and when you judge it necessary, you can change the value of the Boolean
variable by assigning it a true or false value. Here is an example:
using System;
DrinkingUnderAge = false;
Console.WriteLine("Drinking Under Age: {0}", DrinkingUnderAge);
return 0;
}
}
As reviewed for the other data types, you can request the value of a Boolean variable
from the user. In this case, the user must type either True (or true) or False (or false)
and you can retrieve it using the Read() or the ReadLine() methods of the Console
class. Here is an example:
using System;
Like the other types of variables we used in previous lessons, a Boolean variable can be
made a field of a class. You declare it like any other variable, using the bool keyword or
the Boolean data type. Here is an example:
{
public char TypeOfHome;
public int Bedrooms;
public float Bathrooms;
public byte Stories;
public bool HasCarGarage;
public int YearBuilt;
public double Value;
}
return 0;
}
}
Boolean Arguments
Like parameters of the other types, you can pass an argument of type bool or Boolean to
a method. Such an argument would be treated as holding a true or false value.
Enumerations
Introduction
Consider that, when creating a program for a real estate company that sells houses, you
want the program to ask a customer the type of house that he or she wants to purchase
and/or the type of garage that the desired house should have. Here is an example:
using System;
return 0;
}
}
House Type: 3
Garage Type: 1
Press any key to continue . . .
For such a program, the numbers can be vague. 1 can be considered a general number
but, in our program, it can represent a Single Family house or an Interior type of garage.
At the same time, our program uses the constant 1 in particular meaningful ways. To
make it possible to give more meaning to a constant number, when the number can be
made part of a series, C# allows you to create a type of list.
An enumeration is a series of constant integers that each has a specific position in the list
and can be recognized by a meaningful name. Based on this, instead of just remembering
that the constant 1 represents Single Family, you can create a list that has that type of
house. In another list, instead of using 1 again, you can give it a name. Consequently, in
each list, although the constant 1 would still be considered, at least it would mean
something precise.
To create an enumeration, you use the enum keyword, followed by the name of the
enumeration, followed by a name for each item of the list. The name of the enumerator
and the name of each item of the list follows the rules we reviewed for names. The
formula of creating an enumeration is:
enum Series_Name {Item1, Item2, Item_n};
Here is an example:
using System;
return 0;
}
}
Just as done with the other types, you can use the var keyword to declare a variable of
an enumeration type.
After declaring a variable for an enumeration, to initialize it, specify which member of the
enumeration would be assigned to the variable. You should only assign a known member
of the enumeration. To do this, on the right side of the assignment operator, type the
name of the enumeration, followed by the period operator, and followed by the member
whose value you want to assign. Here is an example:
using System;
return 0;
}
}
You can also find out what value the declared variable is currently holding. For example,
you can display it on the console using Write() or WriteLine(). Here is an example:
using System;
return 0;
}
}
An enumeration is in fact a list of numbers where each member of the list is identified with
a name. By default, the first item of the list has a value of 0, the second has a value of 1,
and so on. For example, on the HouseType enumeration, Unknown has a value of 0 while
Townhouse has a value of 2. These are the default values. If you don't want these values,
you can specify the value of one or each member of the list. Suppose you want the
Unknown member in the above enumeration to have a value of 5. To do this, use the
assignment operator "=" to give the desired value. The enumerator would be:
using System;
In this case, Unknown now would have a value of 5, SingleFamily would have a value of 6
because it follows a member whose value is 1 (thus 5 + 1 = 6). Townhouse would have a
value of 7, and Condominium would have a value of 8. You can also assign a value to
more than one member of an enumeration. Here is an example:
using System;
In this case, Townhouse would have a value of 13 because it follows SingleFamily that has
a value of 12.
Enumerations Visibility
By default, if you create an enumeration the way we have proceeded so far, it would be
available only in the project it belongs to. As done for a class, you can control an
enumeration's accessibility outside of its project. This means that you can hide or make it
visible outside of its project. To do this, you can precede it with the private or the
public keyword. Here is an example:
using System;
After creating an enumeration, you can use it as a data type to declare a variable. To
create a field that is of an enumeration type, follow the same rules as done for the
primitive types: the name of the enumeration, followed by the name of the variable, and
followed by a semi-colon. Here is an example:
public enum HouseType
{
Unknown,
SingleFamily,
TownHouse,
Condominium
}
In the same way, you can declare as many enumeration variables as you want. After
declaring the variable, to initialize it, assign it the desired member of the enumeration.
Here is an example:
public enum HouseType
{
Unknown,
SingleFamily,
TownHouse,
Condominium
}
public House()
{
PropertyType = HouseType.Unknown;
}
}
using System;
public House()
{
PropertyType = HouseType.Unknown;
}
propType.PropertyType = HouseType.SingleFamily;
propType.Display();
Console.WriteLine();
return 0;
}
}
Using it as normal data type, you can create a method that returns an enumeration. You
can also pass an enumeration to a method as argument.
namespace FlowerShop1
{
public enum FlowerType
{
Roses = 1,
Lilies,
Daisies,
Carnations,
LivePlant,
Mixed
}
public Flower()
{
Type = FlowerType.Mixed;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type)
{
Type = type;
Color = FlowerColor.Mixed;
C# 3.0 Practical Learning 193
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type, FlowerColor color,
FlowerArrangement argn, decimal price)
{
Type = type;
Color = color;
Arrangement = argn;
UnitPrice = price;
}
}
}
namespace FlowerShop1
{
public class Program
{
private static OrderProcessing CreateFlowerOrder()
{
OrderProcessing order = new OrderProcessing();
int type, color, qty;
int arrangement;
decimal price;
Console.WriteLine("=======================");
Console.WriteLine("==-=-=Flower Shop=-=-==");
Console.WriteLine("-----------------------");
return order;
}
ShowFlowerOrder(flower);
Console.WriteLine();
}
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: LivePlant
Flower Color: Lavender
Arrangement: Basket
Price: $35.95
Quantity: 4
Total Price: $143.80
=======================
Logical Operators
Introduction
A program is a series of instructions that ask the computer (actually the compiler) to
check some situations and to act accordingly. To check such situations, the computer
spends a great deal of its time performing comparisons between values. A comparison is a
Boolean operation that produces a true or a false result, depending on the values on
which the comparison is performed.
A comparison is performed between two values of the same type; for example, you can
compare two numbers, two characters, or the names of two cities. On the other hand, a
comparison between two disparate values doesn't bear any meaning. For example, it is
C# 3.0 Practical Learning 196
difficult to compare a telephone number and somebody's age, or a music category and the
distance between two points. Like the binary arithmetic operations, the comparison
operations are performed on two values. Unlike arithmetic operations where results are
varied, a comparison produces only one of two results. The result can be a logical true or
a logical false. When a comparison is true, it has an integral value of 1 or positive; that is,
a value greater than 0. If the comparison is not true, it is considered false and carries an
integral value of 0.
The C# language is equipped with various operators used to perform any type of
comparison between similar values. The values could be numeric, strings, or objects
(operations on objects are customized in a process referred to as Operator Overloading).
There are primary assumptions you should make when writing statements used in
conditions:
Simplicity and Clarity: A statement should be clear enough and possibly simple but
as complete as possible. When a statement becomes long, it can lead to being
segmented in short parts, which deceives its clarity and may create other issues.
Factual: The statement must be presented as fact and not as opinion. This means
that you don't have to like the statement but the majority, including you, must
agree that it is true or it is false. In fact, the statement doesn't have to be correct
but it must be agreed upon to be true. Based on this, a statement such as "An hour
contains 45 minutes" doesn't have to fit your way of thinking but it must be
considered as true or as false. A statement such as "This job applicant is attractive"
is an opinion and therefore must not be considered in a conditional statement.
Inverse: A statement must be able to find its reverse. This means that, when a
statement is made and decided upon to be true or false, an inverse statement must
be found to make it false or true. For example, if you have a statement such as
"This job applicant is 18 years old", you must be able to state that "This job
applicant is not 18 years old" or "This job applicant is younger than 18".
In your programs, make sure you clearly formulate your statements. This would make
your programs easy to read and troubleshoot when problems occur (not if, but when).
To compare two variables for equality, C# uses the == operator. The formula used is:
Value1 == Value2
The equality operation is used to find out whether two variables (or one variable and a
constant) hold the same value. From our syntax, the compiler would compare the value of
Value1 with that of Value2. If Value1 and Value2 hold the same value, the comparison
produces a true result. If they are different, the comparison renders false.
Console.Write("Value 1 = ");
Console.WriteLine(Value1);
Console.Write("Value 2 = ");
Console.WriteLine(Value2);
Console.Write("Comparison of Value1 == 15 produces ");
Console.WriteLine(Value1 == 15);
return 0;
}
}
It is important to make a distinction between the assignment "=" and the logical equality
operator "==". The first is used to give a new value to a variable, as in Number = 244.
The operand on the left side of = must always be a variable and never a constant. The
== operator is never used to assign a value; this would cause an error. The == operator
is used only to compare to values. The operands on both sides of == can be variables,
constants, or one can be a variable while the other is a constant. If you use one operator
in place of the other, you would receive an error when you compile the program.
There are two main ways you can use the logical not operator. As we will learn when
studying conditional statements, the most classic way of using the logical not operator is
to check the state of a variable.
To nullify a variable, you can write the exclamation point to its left. Here is an example:
using System;
Console.Write("HasAirCondition = ");
Console.WriteLine(HasAirCondition);
DoesIt = !HasAirCondition;
Console.Write("DoesIt = ");
Console.WriteLine(DoesIt);
return 0;
}
}
When a variable holds a value, it is "alive". To make it not available, you can "not" it.
When a variable has been "notted", its logical value has changed. If the logical value was
true, which is 1, it would be changed to false, which is 0. Therefore, you can inverse the
logical value of a variable by "notting" or not "notting" it.
As opposed to Equality, C# provides another operator used to compare two values for
inequality. This operation uses a combination of equality and logical not operators. It
combines the logical not ! and a simplified == to produce !=. Its syntax is:
Value1 != Value2
The != is a binary operator (like all logical operator except the logical not, which is a unary
operator) that is used to compare two values. The values can come from two variables as
in Variable1 != Variable2. Upon comparing the values, if both variables hold different
C# 3.0 Practical Learning 199
values, the comparison produces a true or positive value. Otherwise, the comparison
renders false or a null value:
Here is an example:
using System;
Console.Write("Value1 = ");
Console.WriteLine(Value1);
Console.Write("Value2 = ");
Console.WriteLine(Value2);
Console.Write("Value3 = ");
Console.Write(Value3);
Console.WriteLine();
return 0;
}
}
To find out whether one value is lower than another, use the < operator. Its syntax is:
Value1 < Value2
The value held by Value1 is compared to that of Value2. As it would be done with other
operations, the comparison can be made between two variables, as in Variable1 <
Variable2. If the value held by Variable1 is lower than that of Variable2, the comparison
produces a true or positive result.
Console.Write("Value 1 = ");
Console.WriteLine(Value1);
Console.Write("Value 2 = ");
Console.WriteLine(Value2);
Console.WriteLine();
return 0;
}
}
The previous two operations can be combined to compare two values. This allows you to
know if two values are the same or if the first is less than the second. The operator used
is <= and its syntax is:
Value1 <= Value2
The <= operation performs a comparison as any of the last two. If both Value1 and
VBalue2 hold the same value, result is true or positive. If the left operand, in this case
Value1, holds a value lower than the second operand, in this case Value2, the result is still
true.
Console.Write("Value 1 = ");
Console.WriteLine(Value1);
Console.Write("Value 2 = ");
Console.WriteLine(Value2);
Console.WriteLine();
return 0;
}
}
When two values of the same type are distinct, one of them is usually higher than the
other. C# provides a logical operator that allows you to find out if one of two values is
greater than the other. The operator used for this operation uses the > symbol. Its syntax
is:
Value1 > Value2
Both operands, in this case Value1 and Value2, can be variables or the left operand can be
a variable while the right operand is a constant. If the value on the left of the > operator
is greater than the value on the right side or a constant, the comparison produces a true
or positive value . Otherwise, the comparison renders false or null:
The greater than or the equality operators can be combined to produce an operator as
follows: >=. This is the "greater than or equal to" operator. Its syntax is:
Value1 >= Value2
A comparison is performed on both operands: Value1 and Value2. If the value of Value1
and that of Value2 are the same, the comparison produces a true or positive value. If the
value of the left operand is greater than that of the right operand,, the comparison
produces true or positive also. If the value of the left operand is strictly less than the value
of the right operand, the comparison produces a false or null result:
== Equality to a == b !=
Greater than or
>= Val1 >= Val2 <
equal to
Incrementing a Variable
We are used to counting numbers such as 1, 2, 3, 4, etc. In reality, when counting such
numbers, we are simply adding 1 to a number in order to get the next number in the
range. The simplest technique of incrementing a value consists of adding 1 to it. After
adding 1, the value or the variable is (permanently) modified and the variable would hold
the new value. This is illustrated in the following example:
// This program studies value incrementing
using System;
Value = Value + 1;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
C# provides a special operator that takes care of this operation. The operator is called the
increment operator and is represented by ++. Instead of writing Value = Value + 1, you
can write Value++ and you would get the same result. The above program can be re-
written as follows:
// This program studies value incrementing
using System;
Value++;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
The ++ is a unary operator because it operates on only one variable. It is used to modify
the value of the variable by adding 1 to it. Every time the Value++ is executed, the
compiler takes the previous value of the variable, adds 1 to it, and the variable holds the
incremented value:
// This program studies value incrementing
using System;
Value++;
Console.Write("Value = ");
Console.WriteLine(Value);
Value++;
Console.Write("Value = ");
Console.WriteLine(Value);
Value++;
Console.Write("Value = ");
Console.WriteLine(Value);
When using the ++ operator, the position of the operator with regard to the variable it is
modifying can be significant. To increment the value of the variable before re-using it, you
should position the operator on the left of the variable:
// This program studies value incrementing
using System;
Console.Write("Value = ");
Console.WriteLine(Value);
Console.Write("Value = ");
Console.WriteLine(++Value);
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
When writing ++Value, the value of the variable is incremented before being called. On
the other hand, if you want to first use a variable, then increment it, in other words, if you
want to increment the variable after calling it, position the increment operator on the right
side of the variable:
// This program studies value incrementing
using System;
Console.Write("Value = ");
Console.WriteLine(Value);
Console.Write("Value = ");
Console.WriteLine(Value++);
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
Decrementing a Value
Value = Value - 1;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
Value--;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
Once again, the position of the operator can be important. If you want to decrement the
variable before calling it, position the decrement operator on the left side of the operand.
This is illustrated in the following program:
// This program studies value decrementing
using System;
Console.Write("Value = ");
Console.WriteLine(--Value);
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
If you plan to decrement a variable only after it has been accessed, position the operator
on the right side of the variable. Here is an example:
// This program studies value decrementing
using System;
Console.Write("Value = ");
Console.WriteLine(Value--);
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
It is not unusual to add or subtract a constant value to or from a variable. All you have to
do is to declare another variable that would hold the new value. Here is an example:
// This program studies value incrementing and decrementing
using System;
return 0;
}
}
The above technique requires that you use an extra variable in your application. The
advantage is that each value can hold its own value although the value of the second
variable depends on whatever would happen to the original or source variable.
Sometimes in your program you will not need to keep the original value of the source
variable. You may want to permanently modify the value that a variable is holding. In this
case you can perform the addition operation directly on the variable by adding the desired
value to the variable. This operation modifies whatever value a variable is holding and
does not need an additional variable.
To add a value to a variable and change the value that the variable is holding, you can
combine the assignment “=” and the addition “+” operators to produce a new operator as
+=
Here is an example:
// This program studies value incrementing and decrementing
using System;
Value += 2.42;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
This program produces the same result as the previous. To decrement the value of a
variable, instead of the addition, use the subtraction and apply the same technique. In the
above program, the variable can have its value decremented by combining the assignment
and the subtraction operations on the variable. This is done with the -= operator. Here is
an example:
Value -= 2.42;
Console.Write("Value = ");
Console.WriteLine(Value);
return 0;
}
}
if a Condition is True
Introduction
A conditional statement is an expression that produces a true or false result. You can use
that result as you see fit. To create the expression, you use the Boolean operators we
studied in the previous lesson. In the previous lesson, we saw only how to perform the
operations and how to get the results, not how to use them. To use the result of a
Boolean operation, the C# programming language provides some specific conditional
operators.
2. To create a new class, on the main menu, click Project -> Add Class...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ElectronicStore2
{
public enum ItemsCategories
{
Unknown,
CablesAndConnectors,
CellPhonesAndAccessories,
Headphones,
DigitalCameras,
PDAsAndAccessories,
TelephonesAndAccessories,
TVsAndVideos,
SurgeProtectors,
Instructional
}
if
Condominium
}
Console.WriteLine("2. Townhouse");
Console.WriteLine("3. Condominium");
Console.Write("You Choice? ");
choice = int.Parse(Console.ReadLine());
The Condition can be the type of Boolean operation we studied in the previous lesson.
That is, it can have the following formula:
Operand1 BooleanOperator Operand2
If the Condition produces a true result, then the compiler executes the Statement. If the
statement to execute is short, you can write it on the same line with the condition that is
being checked. Here is an example:
using System;
If the Statement is too long, you can write it on a different line than the if condition.
Here is an example:
if (choice == 1)
type = HouseType.SingleFamily;
You can also write the Statement on its own line even if the statement is short enough to
fit on the same line with the Condition.
Although the (simple) if statement is used to check one condition, it can lead to
executing multiple dependent statements. If that is the case, enclose the group of
statements between an opening curly bracket “{“ and a closing curly bracket “}”. Here is
an example:
using System;
if (choice == 1)
{
type = HouseType.SingleFamily;
Console.WriteLine("\nDesired House Type: {0}", type);
}
return 0;
}
}
If you omit the brackets, only the statement that immediately follows the condition would
be executed.
Just as you can write one if condition, you can write more than one. Here are examples:
using System;
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
namespace ElectronicStore2
{
public class Program
{
private static StoreItem CreateStoreItem()
{
StoreItem sItem = new StoreItem();
int Category;
Console.WriteLine(
"To create a store item, enter its information");
Console.Write("Item Number: ");
sItem.ItemNumber = long.Parse(Console.ReadLine());
Console.WriteLine("Category");
Console.WriteLine("1. Unknown/Miscellaneous");
Console.WriteLine("2. Cables and Connectors");
Console.WriteLine("3. Cell Phones and Accessories");
Console.WriteLine("4. Headphones");
Console.WriteLine("5. Digital Cameras");
Console.WriteLine("6. PDAs and Accessories");
Console.WriteLine("7. Telephones and Accessories");
Console.WriteLine("8. TVs and Videos - Plasma / LCD");
Console.WriteLine("9. Surge Protector");
Console.WriteLine(
"10. Instructional and Tutorials (VHS & DVD)TVs and
Videos");
Console.Write("Your Choice? ");
category = int.Parse(Console.ReadLine());
if (Category == 1)
sItem.Category = ItemsCategories.Unknown;
if (Category == 2)
sItem.Category = ItemsCategories.CablesAndConnectors;
if (Category == 3)
sItem.Category =
ItemsCategories.CellPhonesAndAccessories;
if (Category == 4)
sItem.Category = ItemsCategories.Headphones;
if (Category == 5)
sItem.Category = ItemsCategories.DigitalCameras;
C# 3.0 Practical Learning 218
if (Category == 6)
sItem.Category = ItemsCategories.PDAsAndAccessories;
if (Category == 7)
sItem.Category =
ItemsCategories.TelephonesAndAccessories;
if (Category == 8)
sItem.Category = ItemsCategories.TVsAndVideos;
if (Category == 9)
sItem.Category = ItemsCategories.SurgeProtectors;
if (Category == 10)
sItem.Category = ItemsCategories.Instructional;
Console.Write("Make: ");
sItem.Make = Console.ReadLine();
Console.Write("Model: ");
sItem.Model = Console.ReadLine();
Console.Write("Unit Price: ");
sItem.UnitPrice = decimal.Parse(Console.ReadLine());
return sItem;
}
Console.WriteLine("");
DescribeStoreItem(saleItem);
}
}
}
if…else
using System;
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
if (type == HouseType.SingleFamily)
Console.WriteLine("\nDesired House Matched");
return 0;
}
}
If you use an if condition to perform an operation and if the result is true, we saw that
you could execute the statement. As we saw in the previous section, any other result
would be ignored. To address an alternative to an if condition, you can use the else
condition. The formula to follow is:
if(Condition)
Statement1;
else
Statement2;
Once again, the Condition can be a Boolean operation like those we studied in the
previous lesson. If the Condition is true, then the compiler would execute Statement1. If
the Condition is false, then the compiler would execute Statement2. Here is an example:
using System;
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
if (type == HouseType.SingleFamily)
Console.WriteLine("Desired House Matched");
else
Console.WriteLine("No House Desired");
return 0;
}
}
1. Access the Program.cs file and, to use the if...else condition, change the file as
follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ElectronicStore2
C# 3.0 Practical Learning 222
{
class Program
{
static StoreItem CreateStoreItem()
{
StoreItem sItem = new StoreItem();
int Category;
double ItemPrice = 0D;
Console.WriteLine(
"To create a store item, enter its information");
Console.Write("Item Number: ");
sItem.ItemNumber = long.Parse(Console.ReadLine());
Console.WriteLine("Category");
Console.WriteLine("1. Unknown/Miscellaneous");
Console.WriteLine("2. Cables and Connectors");
Console.WriteLine("3. Cell Phones and Accessories");
Console.WriteLine("4. Headphones");
Console.WriteLine("5. Digital Cameras");
Console.WriteLine("6. PDAs and Accessories");
Console.WriteLine("7. Telephones and Accessories");
Console.WriteLine("8. TVs and Videos - Plasma / LCD");
Console.WriteLine("9. Surge Protector");
Console.WriteLine(
"10. Instructional and Tutorials (VHS & DVD)TVs and
Videos");
Console.Write("Your Choice? ");
Category = int.Parse(Console.ReadLine());
if (Category == 1)
sItem.Category = ItemsCategories.Unknown;
if (Category == 2)
sItem.Category = ItemsCategories.CablesAndConnectors;
if (Category == 3)
sItem.Category =
ItemsCategories.CellPhonesAndAccessories;
if (Category == 4)
sItem.Category = ItemsCategories.Headphones;
if (Category == 5)
sItem.Category = ItemsCategories.DigitalCameras;
if (Category == 6)
sItem.Category = ItemsCategories.PDAsAndAccessories;
if (Category == 7)
sItem.Category =
ItemsCategories.TelephonesAndAccessories;
if (Category == 8)
sItem.Category = ItemsCategories.TVsAndVideos;
if (Category == 9)
sItem.Category = ItemsCategories.SurgeProtectors;
if (Category == 10)
sItem.Category = ItemsCategories.Instructional;
Console.Write("Make: ");
sItem.Make = Console.ReadLine();
Console.Write("Model: ");
sItem.Model = Console.ReadLine();
Console.Write("Unit Price: ");
ItemPrice = double.Parse(Console.ReadLine());
if( ItemPrice <= 0 )
sItem.UnitPrice = 0.00D;
C# 3.0 Practical Learning 223
else
sItem.UnitPrice = ItemPrice;
return sItem;
}
if (cat == ItemsCategories.CablesAndConnectors)
strCategory = "Cables & Connectors";
if (cat == ItemsCategories.CellPhonesAndAccessories)
strCategory = "Cell Phones & Accessories";
if (cat == ItemsCategories.Headphones)
strCategory = "Headphones";
if (cat == ItemsCategories.DigitalCameras)
strCategory = "Digital Cameras";
if (cat == ItemsCategories.PDAsAndAccessories)
strCategory = "PDAs & Accessories";
if (cat == ItemsCategories.TelephonesAndAccessories)
strCategory = "Telephones & Accessories";
if (cat == ItemsCategories.TVsAndVideos)
strCategory = "TVs & Videos";
if (cat == ItemsCategories.SurgeProtectors)
strCategory = "Surge Protectors";
if (cat == ItemsCategories.Instructional)
strCategory = "Instructional";
return strCategory;
}
Console.WriteLine(strTitle1);
Console.WriteLine(strTitle2);
StoreItem saleItem = CreateStoreItem();
Console.WriteLine("");
Console.WriteLine(strTitle1);
Console.WriteLine(strTitle2);
DescribeStoreItem(saleItem);
Console.WriteLine("");
}
}
C# 3.0 Practical Learning 224
}
=-= Nearson Electronics =-=
******* Store Items ******
To create a store item, enter its information
Item Number: 937494
Category
1. Unknown/Miscellaneous
2. Cables and Connectors
3. Cell Phones and Accessories
4. Headphones
5. Digital Cameras
6. PDAs and Accessories
7. Telephones and Accessories
8. TVs and Videos - Plasma / LCD
9. Surge Protector
10. Instructional and Tutorials (VHS & DVD)TVs and Videos
Your Choice? 5
Make: Canon
Model: EOS 30D
Unit Price: 1395.95
Introduction
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
return 0;
}
}
Suppose a customer responds to these questions: she indicates that she wants single
family house but she cannot afford more than $550,000:
Enter the type of house you want to purchase
1. Single Family
2. Townhouse
3. Condominium
You Choice? 1
Up to how much can you afford? $550000
On the other hand, if we find a house that is less than or equal to $550,000, we retain it:
$550,000 True
One of the ways you can combine two comparisons is by joining them. For our customer, we
want a house to meet BOTH criteria. If the house is a town house, based on the request of
our customer, its conditional value is false. If the house is more than $550,000, the value of
the Boolean Value is true. The Boolean operator used to join two criteria is called AND. This
can be illustrated as follows:
In C#, the Boolean AND operator is performed using the && operator. Here is an
example:
using System;
if(choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
Console.WriteLine("\nDesired House Type: {0}", type);
Console.WriteLine("Maximum value afforded: {0:C}", value);
. . .
Suppose we find a single family home. The first condition is true for our customer. With the
AND Boolean operator, if the first condition is true, then we consider the second criterion.
Suppose that the house we are considering costs $750,500: the price is out of the
customer's range. Therefore, the second condition is false. In the AND Boolean algebra, if
the second condition is false, even if the first is true, the whole condition is false. This would
produce the following table:
class Program
{
static void Main()
{
var type = HouseType.Unknown;
int choice;
var value = 0M;
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
Suppose we find a townhouse that costs $420,000. Although the second condition is true,
the first is false. In Boolean algebra, an AND operation is false if either condition is false:
If we find a single family home that costs $345,000, both conditions are true. In Boolean
algebra, an AND operation is true if BOTH conditions are true. This can be illustrated as
follows:
Condition1
If Condition1 If Condition2
AND
is is
Condition2
As you can see, a logical conjunction is true only of BOTH conditions are true.
Combining Conjunctions
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
return 0;
}
}
We saw that when two conditions are combined, the compiler first checks the first condition,
followed by the second. In the same way, if three conditions need to be considered, the
compiler evaluates the truthfulness of the first condition:
Type of House
Town House
False
If the first condition (or any condition) is false, the whole condition is false, regardless of the
outcome of the other(s). If the first condition is true, then the second condition is evaluated
for its truthfulness:
A B
True False
A B A && B
When evaluating three conditions, if either the first or the second is false, since the whole
condition would become false, there is no reason to evaluate the third. If both the first and
Property Indoor
Type of House
Value Garage
A B C
From our discussion so far, the truth table of the combinations can be illustrated as follows:
A B C A && B && C
The whole combination is true only if all three conditions are true. This can be illustrated as
follows:
Logical Disjunction: OR
Introduction
Our real estate company has single family homes, townhouses, and condominiums. All
of the condos have only one level, also referred to as a story. Some of the single family
homes have one story, some have two and some others have three levels. All
townhouses have three levels.
Another customer wants to buy a home. The customer says that he primarily wants a
condo, but if our real estate company doesn't have a condominium, that is, if the
company has only houses, whatever it is, whether a house or a condo, it must have only
one level (story) (due to an illness, the customer would not climb the stairs). When
considering the properties of our company, we would proceed with these statements:
Condominium True
The other properties would not be considered, especially if they have more than one story:
3 False
C# 3.0 Practical Learning 235
To check for either of two conditions, in Boolean algebra, you can use an operator called OR.
We can show this operation as follows:
In Boolean algebra, this type of comparison is performed using the OR operator. In C#,
the OR operator is performed using the || operator. Here is an example:
using System;
if (choice == 1)
type = HouseType.SingleFamily;
if (choice == 2)
type = HouseType.Townhouse;
if (choice == 3)
type = HouseType.Condominium;
return 0;
}
}
C# 3.0 Practical Learning 236
Here is an example of running the program:
Enter the type of house you want to purchase
1. Single Family
2. Townhouse
3. Condominium
You Choice? 3
How many stories? 6
Suppose that, among the properties our real estate company has available, there is no
condominium. In this case, we would then consider the other properties:
If we have a few single family homes, we would look for one that has only one story. Once
we find one, our second criterion becomes true:
Type of
One Story Condominium OR 1 Story
House
If we find a condo and it is one story, both criteria are true. This can be illustrated in the
following table:
Type of
One Story Condominium OR 1 Story
House
A Boolean OR operation produces a false result only if BOTH conditions ARE FALSE:
Combinations of Disjunctions
As opposed to evaluating only two conditions, you may face a situation that presents
three of them and must consider a combination of more than two conditions.
if Switches
The conditional operator behaves like a simple if…else statement. Its syntax is:
Condition ? Statement1 : Statement2;
The compiler would first test the Condition. If the Condition is true, then it would
execute Statement1, otherwise it would execute Statement2. When you request two
numbers from the user and would like to compare them, the following program would
do find out which one of both numbers is higher. The comparison is performed using the
conditional operator:
using System;
Number1 = int.Parse(Num1);
Number2 = int.Parse(Num2);
Console.WriteLine();
return 0;
C# 3.0 Practical Learning 239
}
}
3. To create a new class, on the main menu, click Project -> Add Class...
namespace FlowerShop2
{
public enum FlowerType
{
Roses = 1,
Lilies,
Daisies,
Carnations,
LivePlant,
Mixed
}
public Flower()
{
Type = FlowerType.Mixed;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type)
{
Type = type;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type, FlowerColor color,
FlowerArrangement argn, decimal price)
{
Type = type;
Color = color;
Arrangement = argn;
UnitPrice = price;
}
}
}
if(Condition1) Statement1;
else if(Condition2) Statement2;
Condominium
}
Console.WriteLine("2. Townhouse");
Console.WriteLine("3. Condominium");
Console.Write("You Choice? ");
Choice = int.Parse(Console.ReadLine());
Notice that only two conditions are evaluated. Any condition other than these two is not
considered. Because there can be other alternatives, the C# language provides an
alternate else as the last resort. Its formula is:
if(Condition1) if(Condition1)
Statement1; Statement1;
else if(Condition2) else if(Condition2)
Statement2; Statement2;
else else if(Condition3)
Statement-n; Statement3;
else
Statement-n;
The compiler will check the first condition. If Condition1 is true, it executes Statement1.
If Condition1 is false, then the compiler will check the second condition. If Condition2 is
true, it will execute Statement2. When the compiler finds a Condition-n to be true, it will
execute its corresponding statement. It that Condition-n is false, the compiler will check
the subsequent condition. This means you can include as many conditions as you see fit
using the else if statement. If after examining all the known possible conditions you
still think that there might be an unexpected condition, you can use the optional single
else. Here is an example:
using System;
if (Choice == 1)
Type = HouseType.SingleFamily;
C# 3.0 Practical Learning 243
else if (Choice == 2)
Type = HouseType.Townhouse;
else if (Choice == 3)
Type = HouseType.Condominium;
else
Type = HouseType.Unknown;
return 0;
}
}
Case Switches
Introduction
When defining an expression whose result would lead to a specific program execution,
the switch statement considers that result and executes a statement based on the
possible outcome of that expression, this possible outcome is called a case. The different
outcomes are listed in the body of the switch statement and each case has its own
execution, if necessary. The body of a switch statement is delimited from an opening to
a closing curly brackets: “{“ to “}”. The syntax of the switch statement is:
switch(Expression)
{
case Choice1:
Statement1;
break;
case Choice2:
Statement2;
break;
case Choice-n:
Statement-n;
In C++, you can omit the break keyword in a case. This creates the "fall through"
effect as follows: after code executes in a case, if nothing "stops" it, the execution
continues to the next case. This has caused problems and confusing execution in
the past in some C++ programs. To avoid it, C# requires code interruption at the
end of every case. This interruption is done using the break keyword.
switch (Choice)
{
case 1:
Type = HouseType.SingleFamily;
break;
case 2:
Type = HouseType.Townhouse;
break;
case 3:
Type = HouseType.Condominium;
break;
}
return 0;
}
}
When establishing the possible outcomes that the switch statement should consider, at
times there will be possibilities other than those listed and you will be likely to consider
them. This special case is handled by the default keyword. The default case would
be considered if none of the listed cases matches the supplied answer. The syntax of the
switch statement that considers the default case would be:
switch(Expression)
{
case Choice1:
Statement1;
break;
case Choice2:
Statement2;
break;
case Choice-n:
Statement-n;
break;
default:
Other-Possibility;
break;
}
In C++, the default section doesn't need a break keyword because it is the
last. In C#, every case and the default section must have its own exit
mechanism, which is taken care of by a break keyword.
switch (Choice)
{
case 1:
Type = HouseType.SingleFamily;
break;
case 2:
Type = HouseType.Townhouse;
break;
case 3:
Type = HouseType.Condominium;
break;
default:
Type = HouseType.Unknown;
break;
}
return 0;
}
}
Besides a value of an int type, you can also use another variant of integers on a
switch statement. For example, you can use letters to validate the cases. Here is an
example:
using System;
C# 3.0 Practical Learning 247
public enum HouseType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
switch (Choice)
{
case 1:
Type = HouseType.SingleFamily;
break;
case 2:
Type = HouseType.Townhouse;
break;
case 3:
Type = HouseType.Condominium;
break;
default:
Type = HouseType.Unknown;
break;
}
case 'Y':
Garage = "Yes";
break;
case 'n':
Garage = "No";
break;
default:
Garage = "Not Specified";
break;
}
return 0;
}
}
1. To create a new class, in the Solution Explorer, right-click the project name,
position the mouse on Add and click Class...
namespace FlowerShop2
{
class OrderProcessing
{
public Flower FlowerOrder;
public int Quantity;
public OrderProcessing()
{
FlowerOrder = new Flower();
}
switch (choice)
{
case 1:
FlowerOrder.Type = FlowerType.Roses;
break;
case 2:
FlowerOrder.Type = FlowerType.Lilies;
break;
case 3:
FlowerOrder.Type = FlowerType.Daisies;
break;
case 4:
FlowerOrder.Type = FlowerType.Carnations;
break;
case 5:
FlowerOrder.Type = FlowerType.LivePlant;
break;
default:
FlowerOrder.Type = FlowerType.Mixed;
break;
}
}
switch (choice)
{
case 1:
FlowerOrder.Color = FlowerColor.Red;
break;
C# 3.0 Practical Learning 250
case 2:
FlowerOrder.Color = FlowerColor.White;
break;
case 3:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 4:
FlowerOrder.Color = FlowerColor.Pink;
break;
case 5:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 6:
FlowerOrder.Color = FlowerColor.Blue;
break;
case 7:
FlowerOrder.Color = FlowerColor.Lavender;
break;
default:
FlowerOrder.Color = FlowerColor.Mixed;
break;
}
}
switch (choice)
{
case 1:
FlowerOrder.Arrangement = FlowerArrangement.Bouquet;
break;
case 2:
FlowerOrder.Arrangement = FlowerArrangement.Vase;
break;
case 3:
FlowerOrder.Arrangement = FlowerArrangement.Basket;
break;
default:
FlowerOrder.Arrangement = FlowerArrangement.Any;
break;
}
}
namespace FlowerShop2
{
class Program
{
static void Main()
{
OrderProcessing order = new OrderProcessing();
order.ProcessOrder();
Console.WriteLine();
order.ShowOrder();
Console.WriteLine();
}
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: Carnations
Flower Color: Lavender
Arrangement: Basket
Price: $45.85
Quantity: 3
Total Price: $137.55
=======================
Combining Cases
Each of the cases we have used so far examined only one possibility before executing
the corresponding statement. You can combine cases to execute the same statement.
To do this, type a case, its value, and the semi-colon. Type another case using the same
formula. When the cases are ready, you can then execute the desired statement. Here is
an example:
using System;
switch (Choice)
{
case 1:
Type = HouseType.SingleFamily;
break;
case 2:
Type = HouseType.Townhouse;
break;
case 3:
Type = HouseType.Condominium;
break;
default:
Type = HouseType.Unknown;
break;
}
case 'n':
case 'N':
Garage = "No";
break;
default:
Garage = "Not Specified";
break;
}
return 0;
}
}
Using Enumerations
switch ((HouseType)Choice)
{
case HouseType.SingleFamily:
PropertyType = "Single Family";
break;
case HouseType.Townhouse:
PropertyType = "Townhouse";
break;
case HouseType.Condominium:
PropertyType = "Condominium";
break;
default:
PropertyType = "Unknown";
break;
}
case 'n':
case 'N':
Garage = "No";
break;
default:
Garage = "Not Specified";
break;
}
return 0;
}
}
Conditional Looping
Introduction
A loop is a type of conditional statement that keeps checking a condition and executing
a statement until the condition is false.
One of the operators used to perform a loop is called while. Its formula is:
while(Condition) Statement;
To execute this expression, the compiler first examines the Condition. If the Condition is
true, then it executes the Statement. After executing the Statement, the Condition is
checked again. AS LONG AS the Condition is true, it will keep executing the Statement.
When or once the Condition becomes false, it exits the loop:
Here is an example:
using System;
Console.WriteLine();
return 0;
}
}
To effectively execute a while condition, you should make sure you provide a
mechanism for the compiler to use or get a reference value for the condition, variable,
or expression being checked. This is sometimes in the form of a variable being initialized
although it could be some other expression. Such a while condition could be illustrated
as follows:
The while loop is used first check a condition and then execute a statement. If the
condition is false, the statement would never execute. Consider the following program:
using System;
C# 3.0 Practical Learning 258
public class Exercise
{
public static int Main()
{
var Stories = 5;
Console.WriteLine();
return 0;
}
}
When this program executes, nothing from the while loop would execute because, as
the condition is checked in the beginning, it is false and the compiler would not get to
the Statement. In some cases, you may want to execute a statement before checking
the condition for the first time. This can be done using the do…while statement. Its
formula is:
do Statement while (Condition);
The do…while condition executes a Statement first. After the first execution of the
Statement, it examines the Condition. If the Condition is true, then it executes the
Statement again. It will keep executing the Statement AS LONG AS the Condition is true.
Once the Condition becomes false, the looping (the execution of the Statement) would
stop.
If the Statement is a short one, such as made of one line, simply write it after the do
keyword. Like the if and the while statements, the Condition being checked must be
included between parentheses. The whole do…while statement must end with a
semicolon.
do
Console.WriteLine("Number {0}", Stories++);
while (Stories <= 4);
Console.WriteLine();
return 0;
}
}
If the Statement is long and should span more than one line, start it with an opening
curly bracket "{" and end it with a closing curly bracket "}".
3. To create a new class, in the Class View, right-click the project name -> Add ->
Class...
namespace FlowerShop3
{
public enum FlowerType
{
Roses = 1,
Lilies,
Daisies,
Carnations,
LivePlant,
Mixed
}
class Flower
{
public FlowerType Type;
public FlowerColor Color;
public FlowerArrangement Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = FlowerType.Mixed;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type)
{
Type = type;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
UnitPrice = 0.00M;
}
public Flower(FlowerType type, FlowerColor color,
FlowerArrangement argn, decimal price)
{
Type = type;
Color = color;
Arrangement = argn;
UnitPrice = price;
}
}
}
6. To create a new class, in the Solution Explorer, right-click the project name,
position the mouse on Add and click Class...
namespace FlowerShop3
{
class OrderProcessing
{
public Flower FlowerOrder;
public int Quantity;
public OrderProcessing()
{
FlowerOrder = new Flower();
}
do
{
Console.WriteLine("Enter the Type of Flower Order");
Console.WriteLine("1. Roses");
Console.WriteLine("2. Lilies");
Console.WriteLine("3. Daisies");
Console.WriteLine("4. Carnations");
Console.WriteLine("5. Live Plant");
Console.WriteLine("6. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
} while ((choice < 1) || (choice > 6));
switch (choice)
{
case 1:
FlowerOrder.Type = FlowerType.Roses;
break;
case 2:
FlowerOrder.Type = FlowerType.Lilies;
break;
case 3:
FlowerOrder.Type = FlowerType.Daisies;
break;
case 4:
FlowerOrder.Type = FlowerType.Carnations;
break;
case 5:
FlowerOrder.Type = FlowerType.LivePlant;
break;
default:
FlowerOrder.Type = FlowerType.Mixed;
break;
}
C# 3.0 Practical Learning 262
}
do
{
Console.WriteLine("Enter the Color");
Console.WriteLine("1. Red");
Console.WriteLine("2. White");
Console.WriteLine("3. Yellow");
Console.WriteLine("4. Pink");
Console.WriteLine("5. Orange");
Console.WriteLine("6. Blue");
Console.WriteLine("7. Lavender");
Console.WriteLine("8. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
} while ((choice < 1) || (choice > 8));
switch (choice)
{
case 1:
FlowerOrder.Color = FlowerColor.Red;
break;
case 2:
FlowerOrder.Color = FlowerColor.White;
break;
case 3:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 4:
FlowerOrder.Color = FlowerColor.Pink;
break;
case 5:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 6:
FlowerOrder.Color = FlowerColor.Blue;
break;
case 7:
FlowerOrder.Color = FlowerColor.Lavender;
break;
default:
FlowerOrder.Color = FlowerColor.Mixed;
break;
}
}
do
{
Console.WriteLine("Enter the Type of Arrangement");
Console.WriteLine("1. Bouquet");
Console.WriteLine("2. Vase");
Console.WriteLine("3. Basket");
C# 3.0 Practical Learning 263
Console.WriteLine("4. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
} while ((choice < 1) || (choice > 4));
switch (choice)
{
case 1:
FlowerOrder.Arrangement = FlowerArrangement.Bouquet;
break;
case 2:
FlowerOrder.Arrangement = FlowerArrangement.Vase;
break;
case 3:
FlowerOrder.Arrangement = FlowerArrangement.Basket;
break;
default:
FlowerOrder.Arrangement = FlowerArrangement.Any;
break;
}
}
order.ProcessOrder();
Console.WriteLine();
order.ShowOrder();
Console.WriteLine();
}
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: Lilies
Flower Color: Lavender
Arrangement: Vase
Price: $42.85
Quantity: 2
Total Price: $85.70
=======================
for
The for statement is typically used to count a number of items. At its regular structure,
it is divided in three parts. The first section specifies the starting point for the count. The
second section sets the counting limit. The last section determines the counting
frequency. The syntax of the for statement is:
for(Start; End; Frequency) Statement;
The Start expression is a variable assigned the starting value. This could be Count = 0;
The End expression sets the criteria for ending the counting. An example would be
Count < 24; this means the counting would continue as long as the Count variable is
less than 24. When the count is about to rich 24, because in this case 24 is excluded,
The Frequency expression would let the compiler know how many numbers to add or
subtract before continuing with the loop. This expression could be an increment
operation such as ++Count.
Console.WriteLine();
return 0;
}
}
do
{
Console.WriteLine("What Type of House Would you Like to
Purchase?");
Console.WriteLine("1 - Single Family");
Console.WriteLine("2 - Town House");
Console.WriteLine("3 - Condominium");
Console.Write("Your Choice? ");
TypeOfHome = int.Parse(Console.ReadLine());
if (TypeOfHome == 1)
Console.WriteLine("\nType of Home: Single Family");
else if (TypeOfHome == 2)
Console.WriteLine("\nType of Home: Town House");
else if (TypeOfHome == 3)
Console.WriteLine("\nType of Home: Condominium");
Console.WriteLine();
return 0;
}
}
This is used to request one of the numbers 1, 2, or 3 from the user. Any number below
1 or above 3 is not accepted. Here is an example of running the program:
What Type of House Would you Like to Purchase?
1 - Single Family
2 - Town House
3 - Condominium
Your Choice? 8
What Type of House Would you Like to Purchase?
1 - Single Family
2 - Town House
3 - Condominium
Your Choice? 6
What Type of House Would you Like to Purchase?
1 - Single Family
2 - Town House
3 - Condominium
Your Choice? 3
If the user enters an invalid value, the question is simply being asked again. It would be
professional to let the user know why the request came back even though what appears
as a normal number was entered. To solve this and other types of problems, you can
write one conditional statement inside of another. This is referred to as nesting. To
create a conditional statement inside of another, simply proceed as we have done so far
to create them. Here is an example:
using System;
do
{
Console.WriteLine("What Type of House Would you Like to
Purchase?");
Console.WriteLine("1 - Single Family");
Console.WriteLine("2 - Townhouse");
Console.WriteLine("3 - Condominium");
if (TypeOfHome == 1)
Console.WriteLine("\nType of Home: Single Family");
else if (TypeOfHome == 2)
Console.WriteLine("\nType of Home: Townhouse");
else if (TypeOfHome == 3)
Console.WriteLine("\nType of Home: Condominium");
Console.WriteLine();
return 0;
}
}
namespace FlowerShop3
{
class OrderProcessing
{
public Flower FlowerOrder;
public int Quantity;
C# 3.0 Practical Learning 269
public OrderProcessing()
{
FlowerOrder = new Flower();
}
do
{
Console.WriteLine("Enter the Type of Flower Order");
Console.WriteLine("1. Roses");
Console.WriteLine("2. Lilies");
Console.WriteLine("3. Daisies");
Console.WriteLine("4. Carnations");
Console.WriteLine("5. Live Plant");
Console.WriteLine("6. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
switch (choice)
{
case 1:
FlowerOrder.Type = FlowerType.Roses;
break;
case 2:
FlowerOrder.Type = FlowerType.Lilies;
break;
case 3:
FlowerOrder.Type = FlowerType.Daisies;
break;
case 4:
FlowerOrder.Type = FlowerType.Carnations;
break;
case 5:
FlowerOrder.Type = FlowerType.LivePlant;
break;
default:
FlowerOrder.Type = FlowerType.Mixed;
break;
}
}
switch (choice)
{
case 1:
FlowerOrder.Color = FlowerColor.Red;
break;
case 2:
FlowerOrder.Color = FlowerColor.White;
break;
case 3:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 4:
FlowerOrder.Color = FlowerColor.Pink;
break;
case 5:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 6:
FlowerOrder.Color = FlowerColor.Blue;
break;
case 7:
FlowerOrder.Color = FlowerColor.Lavender;
break;
default:
FlowerOrder.Color = FlowerColor.Mixed;
break;
}
}
do
{
Console.WriteLine("Enter the Type of Arrangement");
Console.WriteLine("1. Bouquet");
Console.WriteLine("2. Vase");
Console.WriteLine("3. Basket");
Console.WriteLine("4. Mixed");
C# 3.0 Practical Learning 271
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
switch (choice)
{
case 1:
FlowerOrder.Arrangement = FlowerArrangement.Bouquet;
break;
case 2:
FlowerOrder.Arrangement = FlowerArrangement.Vase;
break;
case 3:
FlowerOrder.Arrangement = FlowerArrangement.Basket;
break;
default:
FlowerOrder.Arrangement = FlowerArrangement.Any;
break;
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: Carnations
Flower Color: Yellow
Arrangement: Basket
Price: $54.95
Quantity: 1
Total Price: $54.95
=======================
The break statement is used to stop a loop for any reason or condition when necessary.
The formula of the break statement is:
break;
Although made of only one word, the break statement is a complete statement;
therefore, it can (and should always) stay on its own line (this makes the program easy
to read).
The break statement applies to the most previous conditional statement to it; provided
that previous statement is applicable. The break statement can be used in a while
condition, in a do…while or a for loops to stop an ongoing action. Here is an example
that is used to count the levels of a house from 1 to 12 but it is asked to stop at 3:
using System;
Console.WriteLine();
return 0;
}
}
C# 3.0 Practical Learning 274
This would produce:
Story 1
Story 2
Story 3
When processing a loop, if the statement finds a false value, you can use the continue
statement inside of a while, a do…while or a for conditional statements to ignore the
subsequent statement or to jump from a false Boolean value to the subsequent valid
value, unlike the break statement that would exit the loop. Like the break statement,
the continue keyword applies to the most previous conditional statement and should
stay on its own line. Here is an example when a program is supposed to count the levels
of a house from 1 to 6:
using System;
Console.WriteLine();
return 0;
}
}
The goto statement allows a program execution to jump to another section of the
function in which it is being used. In order to use the goto statement, insert a name on
CountUpTo3:
Console.WriteLine("Our homes have only up to 3 levels\n");
return 0;
}
}
Conditional Return
Some functions are meant to return a value that is conditional of their processing. The
fact that a function indicates the type of value it would return may not be clear at the
time the function is closed but a function defined other than void must always return a
value. You can write a conditional statement, such as if, inside of a function and return a
value from that condition. Here is an example:
using System;
switch (Type)
{
case HouseType.SingleFamily:
Console.WriteLine("\nType of Home: Single Family");
break;
case HouseType.Townhouse:
C# 3.0 Practical Learning 276
Console.WriteLine("\nType of Home: Townhouse");
break;
case HouseType.Condominium:
Console.WriteLine("\nType of Home: Condominium");
break;
case HouseType.Unknown:
Console.WriteLine("\nType of Home. Unknown");
break;
}
return 0;
}
if (Type == 1)
return HouseType.SingleFamily;
else if (Type == 2)
return HouseType.Townhouse;
else if (Type == 3)
return HouseType.Condominium;
}
}
This GetHouseType() method indicates when one of three values is returned. In reality,
this method could get a value other than the three that are considered. If the user
enters such a value, the current version of the method would not know what to do. For
this reason, the program will not compile. In Microsoft Visual C#, you would receive the
following error:
'Program.GetHouseType()': not all code paths return a value
To solve this problem, you must provide a statement that would include any value other
than those considered. You can do this by writing a final return that has its own value.
Here is an example:
using System;
switch (Type)
{
case HouseType.SingleFamily:
return 0;
}
if (Type == 1)
return HouseType.SingleFamily;
else if (Type == 2)
return HouseType.Townhouse;
else if (Type == 3)
return HouseType.Condominium;
else
return HouseType.Unknown;
}
}
Recursion
Introduction
Imagine that you want to count the positive odd numbers from a certain maximum to a
certain minimum. For example, to count the odd numbers from 1 to 9, you would use:
9, 7, 5, 3, and 1
Notice that, to perform this operation, you consider the highest. Then you subtract 2 to
get the previous. Again, you subtract 2 from the number to get the previous. What you
are simply doing is to subtract a constant to what you already have and you invent very
little. In computer programming, you can solve this type of problem by first writing a
function, and then have the function call itself. This is the basis for recursion.
A recursive method starts with a return value. If it would not return a value, you can
define it with void. After its name, the method can take one or more arguments. Most
of the time, a recursive method takes at least one argument that it would then modify.
In the body of the method, you can take the necessary actions. There are no particular
steps to follow when implementing a recursive method but there are two main rules to
observe:
Before or after calling itself, the method must check a condition that would allow it
to stop, otherwise, it might run continuously
For our example of counting decrementing odd numbers, you could start by creating a
method that takes an integer as argument. To exercise some control on the lowest
possible values, we will consider only positive numbers. In the body of the method, we
will display the current value of the argument, subtract 2, and recall the method itself.
Here is our function:
using System;
Console.WriteLine("Odd Numbers");
OddNumbers(Number);
Console.WriteLine();
return 0;
}
}
Notice that the method calls itself in its body. This would produce:
Odd Numbers
9, 7, 5, 3, 1,
Press any key to continue . . .
Recursive methods provide a valuable mechanism for building lists or series, which are value
that are either increment or decrement but follow a pattern. Imagine that, instead of simply
displaying odd numbers as we did above, you want to add them incrementally. If you have
1, it would also produce 1. If you have 5, you would like to add 1 to 3, then the result to 5,
and so on. This can be illustrated as follows:
1
= 1
1 + 3
= 4
1 + 3 + 5
= 9
1 + 3 + 5 + 7
= 16
1 + 3 + 5 + 7 + 9
= 25
To perform this operation, you would consider 1. If the number is less than or equal to
1, the method should return 1. Otherwise, add 2 to 1, then add 2 to the new result.
Continue this until you get to the value of the argument. The method can be
implemented as follows:
using System;
Console.WriteLine("Odd Numbers");
OddNumbers(Number);
Console.WriteLine();
Console.WriteLine("Sum of Odds: {0}\n", AdditionalOdd(Number));
return 0;
}
}
Overview of Properties
Introduction
In C++ and Java, when creating the member variables of a class, programmers usually
"hide" these members in private sections (C++) or create them as private (Java). This
technique makes sure that a member variable is not accessible outside of the class so
that the clients of the class cannot directly influence the value of the member variable. If
you create a member variable as private but still want other classes to access or get
the value of such a field, you must then create one or two "accessories", like a door in
which the external classes must pass through to access the field.
A property is a member of a class that plays an intermediary role to a field of the class.
For example, if you have a field of class and that member represents the salary of an
employee, a property can be the "door" that other classes that need the salary must
present their requests to. As such, these external classes cannot just change the salary
or retrieve it as they wish. A property can be used to validate their request, to reject or
to accept them.
A property is used to "filter" access to a field of a class. Therefore, you start by declaring
a (private (if you don't make it private, you may be deceiving the purpose of creating a
property)) field. Here is an example:
using System;
{
public static int Main()
{
return 0;
Obviously this private field cannot be accessed by an outside class. To let the outside
classes access this variable, you would/can create a property. To indicate that you are
creating a property, there is a syntax you must follow. To start, you must create a
member whose formula resembles a method without the parentheses. Since or if the
property will be accessed by only by objects of the same program, you can mark it with
the internal keyword. If the property will be accessed by objects of this and other
programs, you should mark it as public. Therefore, you would start a property as
follows:
public class Square
{
private double _side;
2. To create a new class, on the main menu, click Project -> Add Class...
namespace DepartmentStore2
{
class DepartmentStore
{
private long itemNo;
private string nm;
private string sz;
private decimal price;
}
}
5. To create a property for each member variable, change the ShoppingItem class as
follows:
using System;
namespace DepartmentStore2
{
class ShoppingItem
{
private string itemNo;
private string nm;
private string sze;
private decimal price;
Types of Properties
Property Readers
A property is referred to as read if its role is only to make available the value of the
member variable it represents. To create a read property, in the body of the property,
type the get keyword and create a body for the keyword, using the traditional curly
brackets that delimit a section of code. Here is an example:
public class Square
{
private double _side;
In the body of the get clause, you can implement the behavior that would be used to
make the field's value available outside. The simplest way consists of just returning the
corresponding field. Here is an example:
public class Square
{
private double _side;
A read property is also referred to as read-only property because the clients of the class
can only retrieve the value of the property but they cannot change it. Therefore, if you
create (only) a read property, you should provide the users with the ability to primarily
specify the value of the member variable. To do this, you can create an accessory
method or a constructor for the class . Here is an example of such a constructor:
public class Square
{
private double _side;
public Square(double s)
{
_side = s;
}
}
Once a read property has been created, other classes can access it, for example they
can read its value as follows:
using System;
public Square(double s)
{
_side = s;
}
}
namespace DepartmentStore2
{
class ShoppingItem
{
private long itemNo;
private string nm;
private string sz;
private decimal price;
namespace DepartmentStore2
{
class Program
{
static void Main()
{
long number;
string name;
C# 3.0 Practical Learning 288
string size;
decimal price;
Console.WriteLine("\n================================");
Console.WriteLine("/-/Arrington Department Store/-/");
Console.WriteLine("--------------------------------");
Console.WriteLine("Customer Invoice");
Console.WriteLine("Item #: {0}", store.ItemNumber);
Console.WriteLine("Description: {0}", store.Name);
Console.WriteLine("Item Size: {0}", store.Size);
Console.WriteLine("Unit Price: {0:C}", store.UnitPrice);
Console.WriteLine("================================\n");
}
}
}
/-/Arrington Department Store/-/
Enter the Item #: 622805
Enter the Item Name: Black Leather Hand Bag
Enter the Item Size: Medium
Enter the Unit Price: 85.95
================================
/-/Arrington Department Store/-/
--------------------------------
Customer Invoice
Property Writers
In our Square class so far, we were using a constructor to create a value for each of the
necessary member variables. This meant that we had to always make sure that we knew
the value of the field when we declared an instance of the class. Sometimes, this is not
effective. For example, you cannot just call a constructor in the middle of the program,
that is after the object has been declared, to assign a new value to the field. To solve
this kind of problem, you can provide another means of accessing the field any time to
change its value.
Besides, or instead of, retrieving the value of a field of a class, you may want external
classes to be able to change the value of that member. Continuing with our concern to
hide a field as private, you can create another type of property. A property is referred to
as write if it can change (or write) the value of its corresponding field.
To create a write property, type the set keyword followed by the curly bracket
delimiters. Here is an example:
public class Square
{
private double _side;
The minimum assignment you can perform with a write property is to assign it a value
that would be provided by the outside world. To support this, C# provides the value
contextual keyword (contextual means the word is a keyword only in some cases,
depending on how it is being used). Here is an example:
public class Square
{
private double _side;
As you see, clients of a class can change the corresponding field of a member variable
through the property writer. Based on this relationship, it is not unusual for a client of a
class to make an attempt to "mess" with a field. For example, an external object can
assign an invalid value to a member variable. Consider the following program:
using System;
public Square()
{
_side = 0;
}
public Square(double s)
{
_side = s;
}
sq1._side = -12.48;
sq2._side = 25.55;
return 0;
}
}
Because of this, and since it is through the writer that the external objects would change
the value of the member variable, you can use the write property, rather than the
reader, to validate or reject a new value assigned to the field. Remember that the client
objects of the class can only read the value of the field through the read property.
Therefore, there may be only little concern on that side.
Read/Write Properties
If you create a property that has only a set section, the property is referred to as write-
only because the other classes can only assign it a value (or write a value to it). If you
create a property that has both a get and a set sections, its corresponding member
variable can receive new values from outside the class and the member variable can
provide its values to clients of the class. Such a property is referred to as read/write.
1. To create property writers and complete the program, change the content of the
ShoppingItem.cs file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DepartmentStore2
{
set
{
if (itemNo <= 0)
itemNo = 0;
else
itemNo = value;
}
}
set
{
if (nm == "")
nm = "Item no Description";
else
nm = value;
}
}
set
{
sz = value;
}
}
set
{
if (price < 0)
price = 0.00M;
else
price = value;
}
}
Console.Write("Item #: ");
shop.itemNo = long.Parse(Console.ReadLine());
Console.Write("Item Name: ");
shop.Name = Console.ReadLine();
Console.Write("Item Size (Enter 0 if unknown): ");
shop.Size = Console.ReadLine();
Console.Write("Unit Price: ");
shop.UnitPrice = decimal.Parse(Console.ReadLine());
return shop;
}
namespace DepartmentStore2
{
class Program
{
static void Main()
{
Console.WriteLine("/-/Arrington Department Store/-/");
Console.Write("Enter the following pieces of ");
Console.WriteLine("information about the sale item");
ShoppingItem saleItem = ShoppingItem.Read();
================================
/-/Arrington Department Store/-/
--------------------------------
Item #: 114888
Description: North Hook Alpine Jacket
Item Size: Large
Unit Price: $275.95
Press any key to continue . . .
A Boolean Property
You can create a property as a Boolean type. To do this, first specify its data type as
bool. When treating the property, make sure its get accessory returns a Boolean type.
A Boolean property is not like the other regular properties. It must specify its value as
true or false. As done for Boolean methods, a Boolean property must produce only a
true or false value.
C# 3.0 Practical Learning 295
Properties of External Classes
To create an enumeration property, you use the same formula as one of the primitive
data types we have used previously. Keep it mind that the property is of the type of an
enumeration. This means that you cannot request its value like that of a primitive type
and, when manipulating it, you must process it appropriately.
namespace DepartmentStore2
{
public enum ItemCategory
{
Unspecified,
Women,
Men,
Girls,
Boys,
Babies
}
class ShoppingItem
{
private long itemNo;
private ItemCategory cat;
private string nm;
private string sz;
private decimal price;
set
set
{
cat = value;
}
}
set
{
if (nm == "")
nm = "Item no Description";
else
nm = value;
}
}
set
{
sz = value;
}
}
set
{
if (price < 0)
price = 0.00M;
else
price = value;
}
}
Console.Write("Item #: ");
shop.itemNo = long.Parse(Console.ReadLine());
Console.WriteLine("Store Items Categories");
Console.WriteLine("\t1. Women");
Console.WriteLine("\t2. Men");
Console.WriteLine("\t3. Girls");
Console.WriteLine("\t4. Boys");
Console.WriteLine("\t5. Babies");
Console.Write("Enter the Category: ");
category = int.Parse(Console.ReadLine());
if (category == 1)
shop.Category = ItemCategory.Women;
else if (category == 2)
shop.Category = ItemCategory.Men;
else if (category == 3)
shop.Category = ItemCategory.Girls;
else if (category == 4)
shop.Category = ItemCategory.Boys;
else if (category == 5)
shop.Category = ItemCategory.Babies;
else
shop.Category = ItemCategory.Unspecified;
Console.Write("Item Name: ");
shop.Name = Console.ReadLine();
Console.Write("Item Size (Enter 0 if unknown): ");
shop.Size = Console.ReadLine();
Console.Write("Unit Price: ");
shop.UnitPrice = decimal.Parse(Console.ReadLine());
return shop;
}
/-/Arrington Department Store/-/
Enter the following pieces of
information about the sale item
Item #: 624008
Store Items Categories
1. Women
2. Men
3. Girls
4. Boys
5. Babies
Enter the Category: 3
Item Name: Scotta Miniskirt
Item Size (Enter 0 if unknown): 11
Unit Price: 35.95
================================
/-/Arrington Department Store/-/
--------------------------------
Item #: 624008
Category: Girls
Description: Scotta Miniskirt
Item Size: 11
Unit Price: $35.95
Press any key to continue . . .
A Class as a Property
Remember that, after creating a class, it becomes a data type in its own right. We have
seen that you could declare a variable from it, you could pass it as argument, and you
could return it from a method. As a normal data type, a class can be validated. This
means that its value can be evaluated, rejected, or retrieved. Based on these
characteristics of a class, you can create a property from it.
To create a property that is based on a class, primarily follow the same formulas we
have applied to the other properties. The most important aspect to remember is that the
class is composite. That is, it is (likely) made of fields of various types.
namespace DepartmentStore2
{
public enum ItemCategory
{
Unspecified,
Women,
Men,
Girls,
Boys,
Babies
}
class ShoppingItem
{
private long itemNo;
private ItemCategory cat;
private string nm;
private string sz;
private decimal price;
set
{
itemNo = value;
}
}
set
{
cat = value;
}
}
set
{
if (nm == "")
nm = "Item no Description";
else
nm = value;
}
}
set
{
sz = value;
}
}
set
{
if (price < 0)
price = 0.00M;
else
price = value;
}
}
}
}
2. To create a new class, in the Solution Explorer, right-click the name of the project,
position the mouse on Add and click Class...
namespace DepartmentStore2
{
class DepartmentStore
{
private int qty;
private ShoppingItem itm;
public DepartmentStore()
{
itm = new ShoppingItem();
}
Console.WriteLine("\n================================");
Console.WriteLine("/-/Arrington Department Store/-/");
Console.WriteLine("--------------------------------");
Console.WriteLine("Item #: {0}", itm.ItemNumber);
Console.WriteLine("Category: {0}", itm.Category);
Console.WriteLine("Description: {0}", itm.Name);
Console.WriteLine("Item Size: {0}", itm.Size);
Console.WriteLine("Unit Price: {0:C}", itm.UnitPrice);
Console.WriteLine("Quantity: {0}", Quantity);
Console.WriteLine("Total Price: {0:C}\n", totalPrice);
Console.WriteLine("\n================================");
}
}
}
namespace DepartmentStore2
{
class Program
{
static void Main()
{
C# 3.0 Practical Learning 303
DepartmentStore store = new DepartmentStore();
store.ProcessOrder();
store.DisplayReceipt();
}
}
}
/-/Arrington Department Store/-/
Enter the following pieces of
information about the sale item
Item #: 444412
Store Items Categories
1. Women
2. Men
3. Girls
4. Boys
5. Babies
Enter the Category: 1
Item Name: Stretch Cotton Shirt
Item Size (Enter 0 if unknown): 14
Unit Price: 55.95
How many samples of Stretch Cotton Shirt: 2
================================
/-/Arrington Department Store/-/
--------------------------------
Item #: 444412
Category: Women
Description: Stretch Cotton Shirt
Item Size: 14
Unit Price: $55.95
Quantity: 2
Total Price: $111.90
================================
Press any key to continue . . .
Introduction to Inheritance
Definition
The primary characteristic of the objects on the above pictures is that they are balls
used in different sports. Another characteristic they share is that they are round. On the
other hand, although these balls are used in sport, one made for one sport cannot (or
should not) be used in another sport (of course, it is not unusual for a footballer to
mess with a basketball on a lawn but it is not appropriate). The common characteristics
of these objects can be listed in a group like a C# class. The class would appear as:
class Ball
{
TypeOfSport;
Size;
}
If you were asked to create a class to represent these balls, you may be tempted to
implement a general class that defines each ball. This may be a bad idea because,
despite their round resemblance, there are many internal differences among these balls.
Programming languages like C# provide an alternate solution to this type of situation.
2. To create a new class, in the Class View, right-click the name of the project,
position the mouse on Add and click Class...
namespace RealEstate2
{
public enum PropertyCondition
{
Unknown,
Excellent,
Good,
NeedsRepair,
BadShape
}
public Property()
{
}
5. To create a new class, in the Solution Explorer, right-click the name of the project,
position the mouse on Add and click Class...
namespace RealEstate2
C# 3.0 Practical Learning 308
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
public PropertyListing()
{
prop = new Property();
}
Console.WriteLine("\nTypes of Properties");
Console.WriteLine("1. Single Family");
Console.WriteLine("2. Townhouse");
Console.WriteLine("3. Condonium");
Console.WriteLine("4. Don't Know");
Console.Write("Enter Type of Property: ");
int propType = int.Parse(Console.ReadLine());
switch ((PropertyType)propType)
{
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
break;
case PropertyType.Condominium:
Type = PropertyType.Condominium;
break;
default:
Type = PropertyType.Unknown;
break;
}
ListProperty.Value = decimal.Parse(Console.ReadLine());
}
switch (Type)
{
case PropertyType.SingleFamily:
case PropertyType.Townhouse:
Type = PropertyType.SingleFamily;
break;
case PropertyType.Condominium:
break;
}
Console.WriteLine("Condition: {0}",
C# 3.0 Practical Learning 310
ListProperty.Condition);
Console.WriteLine("Bedrooms: {0}",
ListProperty.Bedrooms);
Console.WriteLine("Bathrooms: {0}",
ListProperty.Bathrooms);
Console.WriteLine("Year Built: {0}",
ListProperty.YearBuilt);
Console.WriteLine("Market Value: {0:C}",
ListProperty.Value);
Console.WriteLine("==================================");
}
}
}
namespace RealEstate2
{
class Program
{
static void Main()
{
PropertyListing listing = new PropertyListing();
listing.CreateListing();
Console.WriteLine("\n");
listing.ShowProperty();
Console.WriteLine();
}
}
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 2
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 2
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 66DG8P
Property Type: Townhouse
Condition: Good
Bedrooms: 2
Bathrooms: 1
Year Built: 1994
Market Value: $325,880.75
==================================
Class Derivation
As you may have guessed, in order to implement inheritance, you must first have a class
that provides the fundamental definition or behavior you need. There is nothing magical
about such a class. It could appear exactly like any of the classes we have used so far.
Here is an example:
using System;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Side: {0}", Round.Radius);
Console.WriteLine("Diameter: {0}", Round.Diameter);
Console.WriteLine("Circumference: {0}", Round.Circumference);
Console.WriteLine("Area: {0}", Round.Area);
return 0;
}
}
The above class is used to process a circle. It can request or provide a radius. It can
also calculate the circumference and the area of a circle. Now, suppose you want to
create a class for a sphere. You could start from scratch as we have done so far. On the
other hand, since a sphere is primarily a 3-dimensional circle, and if you have a class for
a circle already, you can simply create your sphere class that uses the already
implemented behavior of a circle class.
Creating a class that is based on another class is also referred to as deriving a class from
another. The first class serves as parent or base. The class that is based on another
In this formula, you start with the class keyword followed by a name from your class. On
the right side of the name of your class, you must type the : operator, followed by the
name of the class that will serve as parent. Of course, the BaseClass class must have
been defined; that is, the compiler must be able to find its definition. Based on the
above formula, you can create a sphere class based on the earlier mentioned Circle class
as follows:
class Sphere : Circle
{
// The class is ready
}
After deriving a class, it becomes available and you can use it just as you would any
other class. Here is an example:
using System;
class Circle
{
private double _radius;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Side: {0}", Round.Radius);
Console.WriteLine("Diameter: {0}", Round.Diameter);
Console.WriteLine("Circumference: {0}", Round.Circumference);
Console.WriteLine("Area: {0}", Round.Area);
Console.WriteLine("\nSphere Characteristics");
Console.WriteLine("Side: {0}", Ball.Radius);
Console.WriteLine("Diameter: {0}", Ball.Diameter);
Console.WriteLine("Circumference: {0}", Ball.Circumference);
Console.WriteLine("Area: {0}", Ball.Area);
return 0;
}
}
Sphere Characteristics
Side: 25.55
Diameter: 51.1
Circumference: 160.535249
Area: 2050.837805975
Press any key to continue
When a class is based on another class, all public (we will also introduce another
inheritance-oriented keyword for this issue) members of the parent class are made
available to the derived class that can use them as easily. While other methods and
classes can also use the public members of a class, the difference is that the derived
class Circle
{
private double _radius;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Round.ShowCharacteristics();
Ball.Radius = 25.55;
Ball.ShowCharacteristics();
return 0;
}
}
namespace RealEstate2
{
public class HouseType : Property
{
private int nbrOfStories;
private bool basement;
private bool garage;
6. To create another class based on the Property class, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RealEstate2
{
public class Condominium : Property
{
private bool handicap;
namespace RealEstate2
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
C# 3.0 Practical Learning 318
}
class PropertyListing
{
private Property prop;
private HouseType hse;
private Condominium cond;
private PropertyType tp;
{
get { return hse; }
set { hse = value; }
}
{
get { return cond; }
set { cond = value; }
}
public PropertyListing()
{
prop = new Property();
hse = new HouseType();
cond = new Condominium();
}
switch ((PropertyType)propType)
{
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
Console.Write("\nHow many stories (levels)? ");
House.Stories = int.Parse(Console.ReadLine());
Console.Write("Does it have an indoor car garage (y/n):
");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
Console.Write("\nHow many stories (levels)? ");
House.Stories = int.Parse(Console.ReadLine());
Console.Write("Does it have an indoor car garage (y/n):
");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
break;
case PropertyType.Condominium:
C# 3.0 Practical Learning 320
Type = PropertyType.Condominium;
Console.Write("\nIs the building accessible to handicapped (y/n):
");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
Condo.HandicapAccessible = true;
else
Condo.HandicapAccessible = false;
break;
default:
Type = PropertyType.Unknown;
break;
}
switch(Type)
{
case PropertyType.SingleFamily:
case PropertyType.Townhouse:
Type = PropertyType.SingleFamily;
Console.WriteLine("Stories: {0}",
House.Stories);
Console.WriteLine("Has Indoor Car Garage: {0}",
House.IndoorGarage);
Console.WriteLine("Finished Basement: {0}",
House.FinishedBasement);
break;
case PropertyType.Condominium:
Console.WriteLine("Handicapped Accessible Building:
{0}",
Condo.HandicapAccessible);
break;
}
Console.WriteLine("Condition: {0}",
ListProperty.Condition);
Console.WriteLine("Bedrooms: {0}",
ListProperty.Bedrooms);
Types of Properties
1. Single Family
2. Townhouse
3. Condonium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 4LP804
Property Type: SingleFamily
Stories: 3
Has Indoor Car Garage: True
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 4
Bathrooms: 2.5
Year Built: 1996
Market Value: $640,885.80
You can notice in the above example that the derived class produces the same results as
the base class. In reality, inheritance is used to solve various Object-Oriented
Programming (OOP) problems. One of them consists of customizing, adapting, or
improving the behavior of a feature (property or method, etc) of the parent class. For
example, although both the circle and the sphere have an area, their areas are not the
same. A circle is a flat surface but a sphere is a volume, which makes its area very much
higher. Since they use different formulas for their respective area, you should implement
a new version of the area in the sphere. Based on this, when deriving your class from
another class, you should be aware of the properties and methods of the base class so
that, if you know that the parent class has a certain behavior or a characteristic that is
not conform to the new derived class, you can do something about that. A new version
of the area in the sphere can be calculated as follows:
using System;
class Circle
{
private double _radius;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Side: {0}", Round.Radius);
Console.WriteLine("Diameter: {0}", Round.Diameter);
Console.WriteLine("Circumference: {0}", Round.Circumference);
Console.WriteLine("Area: {0}", Round.Area);
Console.WriteLine("\nSphere Characteristics");
Console.WriteLine("Side: {0}", Ball.Radius);
Console.WriteLine("Diameter: {0}", Ball.Diameter);
Console.WriteLine("Circumference: {0}", Ball.Circumference);
Console.WriteLine("Area: {0}", Ball.Area);
return 0;
}
}
Sphere Characteristics
Side: 25.55
Diameter: 51.1
Circumference: 160.535249
Area: 8203.3512239
Notice that, this time, the areas of both figures are not the same even though their radii
are similar.
Besides customizing member variables and methods of a parent class, you can add new
members as you wish. This is another valuable feature of inheritance. In our example,
while the is a flat shape, a sphere has a volume. In this case, you may need to calculate
the volume of a sphere as a new method or property of the derived class. Here is an
example:
using System;
class Circle
{
private double _radius;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Side: {0}", Round.Radius);
Console.WriteLine("Diameter: {0}", Round.Diameter);
Console.WriteLine("Circumference: {0}", Round.Circumference);
Console.WriteLine("Area: {0}", Round.Area);
Console.WriteLine("\nSphere Characteristics");
Console.WriteLine("Side: {0}", Ball.Radius);
Console.WriteLine("Diameter: {0}", Ball.Diameter);
Console.WriteLine("Circumference: {0}", Ball.Circumference);
Console.WriteLine("Area: {0}", Ball.Area);
Console.WriteLine("Volume: {0}\n", Ball.Volume);
return 0;
}
}
Sphere Characteristics
Side: 25.55
Diameter: 51.1
Circumference: 160.535249
Area: 8203.3512239
Volume: 209595.623770645
If you create a property or method in a derived class and that property or method
already exists in the parent class, when you access the property or method in the
derived class, you must make sure you indicate what member you are accessing. To
make this possible, the C# language provides the base keyword. To access a property
or method of a parent class from the derived class, type the base keyword, followed by
the period operator, followed by the name of the property or method of the base class.
Imagine you create a class used to process a circle as we saw earlier. You can use this
as the base class for a sphere. Both the circle and the sphere have an area but their
values are different. This means that, as mentioned in our introduction to inheritance,
when deriving the sphere class, you would have to calculate a new area for the cube.
If you create or declare a new member in a derived class and that member has the
same name as a member of the base class, when creating the new member, you may
want to indicate to the compiler that, instead of overriding that same method that was
defined in the base class, you want to create a brand new and independent version of
that method. When doing this, you would be asking the compiler to hide the member of
the base class that has the same name, when the member of the current class is
invoked. To do this, type the new keyword to its left. Here is an example:
using System;
class Circle
{
private double _radius;
class Exercise
{
public static int Main()
{
var Round = new Circle();
Round.Radius = 25.55;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Side: {0}", Round.Radius);
Console.WriteLine("Diameter: {0}", Round.Diameter);
Console.WriteLine("Circumference: {0}", Round.Circumference);
Console.WriteLine("Area: {0}", Round.Area);
Console.WriteLine("\nSphere Characteristics");
Console.WriteLine("Side: {0}", Ball.Radius);
Console.WriteLine("Diameter: {0}", Ball.Diameter);
Console.WriteLine("Circumference: {0}", Ball.Circumference);
Console.WriteLine("Area: {0}", Ball.Area);
Console.WriteLine("Volume: {0}\n", Ball.Volume);
return 0;
}
}
Characteristics of Inheritance
Imagine you had created a class named Person in a namespace named People as
follows:
Source File: Persons.cs
using System;
namespace People
{
public class Person
{
private string _name;
private string _gdr;
public Person()
{
this._name = "Not Available";
this._gdr = "Unknown";
}
If you decide to derive a class from it, remember that this class belongs to a namespace.
To inherit from this class, the compiler will need to know the namespace in which the
class was created. Class inheritance that involves namespaces relies on qualification, like
the calling of the members of a namespace. To derive a class from a class member of a
namespace, type the name of the namespace, followed by the period operator ".", and
followed by the name of the base namespace. Here is an example:
Source File: StaffMembers.cs
using System;
namespace HighSchool
{
public class Teacher : People.Person
{
private string _pos;
public Teacher()
{
this._pos = "Staff Member";
}
If you need to call the class that was defined in a different namespace, remember to
qualify its name with the period operator. Here is an example:
Source File: Exercise.cs
using System;
class Exercise
{
public static int Main()
{
People.Person man = new People.Person("Hermine Sandt", "Male");
HighSchool.Teacher staff = new HighSchool.Teacher("Vice
Principal");
Console.WriteLine();
return 0;
}
}
using System;
using People;
using HighSchool;
class Exercise
{
public static int Main()
{
Person man = new Person("Hermine Sandt", "Male");
Teacher staff = new Teacher("Vice Principal");
Console.WriteLine();
return 0;
}
}
2. To create a new class, on the main menu, click Project -> Add Class...
namespace Geometry2
{
public class Square
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
}
}
5. To create a new class, on the main menu, click Project -> Add Class...
namespace Geometry2
{
public class Rectangle
{
double _length;
double _height;
public Rectangle()
{
_length = 0.00;
_height = 0.00;
}
8. Save all
Protected Members
To maintain a privileged relationship with its children, a parent class can make a
member available only to classes derived from it. With this relationship, some members
of a parent class have a protected access level. Of course, as the class creator, it is your
job to specify this relationship.
To create a member that derived classes only can access, type the protected keyword
to its left. Here are examples:
Source File: Persons.cs
using System;
public Person()
{
this._name = "Not Available";
this._gdr = "Unknown";
}
public Person(string name, string gender)
{
this._name = name;
this._gdr = gender;
}
You can access protected members only in derived classes. Therefore, if you instantiate
a class outside, you can call only public members:
Source File: Exercise.cs
using System;
class Exercise
{
public static int Main()
{
People.Person man = new People.Person("Hermine Sandt", "Male");
Console.WriteLine("Staff Member");
man.Show();
Console.WriteLine();
return 0;
}
}
If you create a class member and mark it as protected, the classes derived of its parent
class, created in the current program or outside the current program, can access it. If
you want the member to be accessed only by derived classes implemented in the same
program but not derived classes implemented outside of the current program, mark the
member as protected internal. Here are examples:
Source File: Persons.cs
using System;
Virtual Members
We have just mentioned that you can create a new version of a member in a derived
class for a member that already exists in the parent class. After doing this, when you call
that member in your program, you need to make sure that the right member gets called,
the member in the base class or the equivalent member in the derived class.
When you create a base class, if you anticipate that a certain property or method would
need to be redefined in the derived class, you can indicate this to the compiler. On the
other hand, while creating your classes, if you find out that you are customizing a
property or a method that already exists in the base class, you should let the compiler
know that you are providing a new version. In both cases, the common member should
be created as virtual.
To create a virtual member, in the base class, type the virtual keyword to the left of
the property or method. Based on this, the Area property of our Circle class can be
created as follows:
class Circle
{
public virtual double Area
{
get
{
In Microsoft Visual C#, unlike C++, if you omit the virtual keyword, the (Microsoft
Visual C#) compiler would display a warning.
When you derive a class from an abstract class, since the methods (if any) of the
abstract class were not implemented, you must implement each one of them in the
derived class. When customizing virtual members in a derived class, to indicate that a
member is already virtual in the base class and that you are defining a new version, type
the override keyword to the left of its declaration. For example, the Area property in
our Sphere class can be created as follows:
class Sphere : Circle
{
public override double Area
{
get
{
return 4 * Radius * Radius * 3.14159;
}
}
In the same way, when implementing an abstract method of a class, type the override
keyword to its left.
1. To create a new class, on the main menu, click Project -> Add Class...
namespace Geometry2
{
public class ShapeDescription
{
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure " +
C# 3.0 Practical Learning 335
"that has four sides and four angles.";
return Msg;
}
}
}
5. Access the Square.cs file and override the Description method as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry2
{
public class Square : ShapeDescription
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
return Introduction;
}
}
}
namespace Geometry2
{
public class Rectangle : ShapeDescription
{
double _length;
double _height;
public Rectangle()
C# 3.0 Practical Learning 336
{
_length = 0.00;
_height = 0.00;
}
class Exercise
{
static void DisplaySquare(Square S)
{
Console.WriteLine("Square Characteristics");
Console.WriteLine("Description: {0}", S.Description());
}
Console.WriteLine("========================================");
DisplaySquare(Sq);
Console.WriteLine("========================================");
DisplayRectangle(Rect);
Console.WriteLine("========================================");
Abstract Classes
In a program, you can create a class whose role is only meant to provide fundamental
characteristics for other classes. This type of class cannot be used to declare a variable.
Such a class is referred to as abstract. Therefore, an abstract class can be created only
to serve as a parent class for other classes.
To create an abstract class, type the abstract keyword to the left of its name. Here is
an example:
abstract class Ball
{
protected int TypeOfSport;
protected string Dimensions;
}
namespace Geometry2
{
public abstract class ShapeDescription
{
public virtual string Description()
{
string Msg = "A quadrilateral is a geometric figure " +
"that has four sides and four angles.";
C# 3.0 Practical Learning 338
return Msg;
}
}
}
When creating a class that would mainly be used as a base for future inheritance, you
can create one or more properties and make them abstract. To do this, when creating
the property, type the abstract keyword to its left. Because you would not define the
property, you can simply type the get keyword and its semi-colon in the body of the
property.
A method of a class also can be made abstract. An abstract method can be a member of
only an abstract class. If you make a method abstract in a class, you must not
implement the method. To create an abstract method, when creating its class, type the
abstract keyword to the left of the method's name. End the declaration with a semi-
colon and no body for the method since you cannot implement it. Here is an example:
public abstract class Ball
{
protected int TypeOfSport;
protected string Dimensions;
In the same way, you can create as many properties and methods as you see fit. You
can choose what properties and methods to make abstract. This is important for
inheritance.
1. To create an abstract property, access the ShapeDescription.cs file and change its
class as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry2
{
public abstract class ShapeDescription
{
public abstract string Name { get; }
namespace Geometry2
{
public class Square : ShapeDescription
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
{
_side = s;
}
return Introduction;
}
}
}
namespace Geometry2
{
public class Rectangle : ShapeDescription
{
double _length;
double _height;
namespace Geometry2
{
public class Program
{
static void DisplaySquare(Square S)
{
Console.WriteLine("Square Characteristics");
Console.WriteLine("Name: {0}", S.Name);
Console.WriteLine("Description: {0}", S.Description());
}
Console.WriteLine("========================================");
DisplaySquare(Sq);
Console.WriteLine("========================================");
DisplayRectangle(Rect);
Console.WriteLine("========================================");
Console.WriteLine();
}
}
}
Sealed Classes
Any of the classes we have used so far in our lessons can be inherited from. If you
create a certain class and don't want anybody to derive another class from it, you can
mark it as sealed. In other words, a sealed class is one that cannot serve as base for
another class.
To mark a class as sealed, type the sealed keyword to the left of the class keyword.
Here is an example:
public sealed class Ball
{
public int TypeOfSport;
public string Dimensions;
}
There is not much to do about a sealed class. Simply remember that no class can be
derived from it.
Introduction
Imagine you start creating a class and, while implementing or testing it, you find out
that this particular class can be used instead as a general base that other classes can be
derived from. An interface is a special class whose purpose is to serve as a template
that actual classes can be based on. An interface is primarily created like a class: it has a
name, a body and can have members.
To create an interface, instead of the class keyword, you use the interface keyword.
By convention, the name of an interface starts with I. Here is an example:
interface ICourtDimensions
{
}
namespace Geometry2
{
interface IQuadrilateral
{
}
}
As done for a class, the members of an interface are listed in its body. In an interface,
you cannot declare fields like those we have used in other classes. Instead, if you want
some type of member variable, you can create a property. If you create a property in an
interface, you cannot define that property. One of the rules of an interface is that you
cannot define any of its members. This is also valid for its properties. Therefore, if you
create a property in an interface:
You can indicate that it would be write-only by adding an empty setter property to
it. Here is an example:
public interface ICourtDimensions
{
double Length { set; }
}
You can indicate that it would be used to write values to it and to read values from
it. To provide this information, add a getter and a setter accessories to it. Here is
an example:
public interface ICourtDimensions
{
double Length { get; set; }
}
In the same way, you can create as many properties as you judge necessary in an
interface. Besides the properties, an interface can also have other types of members
such as methods. Here is an example of an interface that has one read-only property
named NameOfSport, one read/write property named NumberOfPlayers, and one
method named SportCharacteristics:
public interface IBall
{
int NumberOfPlayers
{
get;
set;
}
string NameOfSport
{
get;
}
void SportCharacteristics();
}
namespace Geometry2
{
interface IQuadrilateral
{
double Area { get; }
}
}
Just as you can derive a class from an interface, you can create an interface that itself is
based on another interface. Here is an example:
public interface ISportType : IBall
{
SportCategory Type
{
get;
}
}
The C# language doesn't allow multiple inheritance, which is the ability to create a class
based on more than one class. Multiple inheritance is allowed only if the bases are
interfaces. To create multiple inheritance, separate the names of interface, with a
comma. Here is an example:
public interface ISportType : IBall, ICourtDimensions
{
SportCategory Type
{
get;
}
}
You can also involve a class as parent in a multiple inheritance scenario but there must
be only one class. Here is an example in which a class called Sports derives from one
class and various interfaces:
public interface Sports: Player, IBall, ICourtDimensions
{
}
namespace Geometry2
{
interface IRightAngle : IQuadrilateral
{
double Base { get; set; }
double Height { get; set; }
double Perimeter { get; }
}
}
namespace Geometry2
{
public class Square : ShapeDescription, IRightAngle
{
. . .
}
}
namespace Geometry2
{
public class Rectangle : ShapeDescription, IRightAngle
{
. . .
}
}
7. Save all
string NameOfSport
{
get;
}
void SportCharacteristics();
}
If you derive a class, from an interface, you must implement all properties that were
created in the interface. This means that you must define them so that, when a variable
is declared of that class, the properties have meaning. In the same way, if you create a
class that is based on an interface, you must implement all methods that were declared
in the interface. If you derive a class from an interface that itself was derived from
another interface, in your class, you must define all properties that were created in the
whole parental lineage and you must implement all methods that were created in the
parent and grant-parent interfaces. Here is an example:
Source File: Sport.cs
using System;
Once the class is ready, you can then use it as you see fit. Here is an example:
Source File: Exercise.cs
using System;
class Exercise
{
Console.WriteLine();
Console.WriteLine();
return 0;
}
}
Sport Characteristics
Name of Sport: Table Tennis
Type of Sport: SinglePlayer
# of Players: 1
Court Dimensions: 23.7m x 8.25m
namespace Geometry2
{
public class Square : ShapeDescription, IRightAngle
{
private double _side;
public Square()
{
_side = 0.00;
}
public Square(double s)
C# 3.0 Practical Learning 349
{
_side = s;
}
return Introduction;
}
namespace Geometry2
{
public class Rectangle : ShapeDescription, IRightAngle
{
double _length;
double _height;
public Rectangle()
{
C# 3.0 Practical Learning 350
_length = 0.00;
_height = 0.00;
}
namespace Geometry2
C# 3.0 Practical Learning 351
{
public class Program
{
static Square CreateASquare()
{
double side;
Sq = CreateASquare();
Rect = CreateARectangle();
Console.WriteLine("============================");
C# 3.0 Practical Learning 352
DisplaySquare(Sq);
Console.WriteLine("============================");
DisplayRectangle(Rect);
Console.WriteLine("============================");
Console.WriteLine();
return 0;
}
}
}
In all of the classes we have defined so far, we were using a single file to implement the
class. In C#, you can create a class (the same class) in different files. This means that
you can start a class in one file and continue it in another file or in other files. This is
referred to as partial implementation.
If you have programmed in C++ or C++/CLI, don't confuse its header and
source files with C#'s partial implementation of classes. In C++ or C++/CLI, you
can include the structure of a class with its member variables (called fields in
C#) and the declaration of its methods. In C++, a header file has the
C# 3.0 Practical Learning 353
extension .h. Here is an example of a C++/CLI header file:
Header File: Cylinder.h
#pragma once
public:
CCylinder(void);
CCylinder(double radius, double height);
double Volume();
};
In C++, after creating a header file, you can create its associated source file.
The source file has the extention .cpp. Here is an example of the source file
corresponding to the above header file:
Source File: Cylinder.cpp
#include "Cylinder.h"
CCylinder::CCylinder(void)
: rad(0.00), hgt(0.00)
{
}
double CCylinder::Volume()
{
return rad * rad * hgt * Math::PI;
}
CCylinder ^ Initialize()
{
CCylinder ^ c = gcnew CCylinder(36.12, 18.84);
return c;
}
int main()
{
CCylinder ^ cyl = Initialize();
Show(cyl);
return 0;
}
As we have seen so far, in C#, you cannot simply and only declare a method in a file for
a forward (later) implementation, as it's done in C, C++, C++/CLI, and (Object) Pascal.
In C#, to create a class in various classes, start the class in one file but precede the
class keyword with partial. Here is an example of a file named first.cs that contains
some (2) private fields and some (2) properties:
Source File: geometry1.cs
using System;
After creating the class in one file, you can use as any of the classes as we have done so
far. Here is an example:
Source File: Exercise.cs
using System;
class Program
{
static Cylinder Initialize()
{
Cylinder c = new Cylinder(36.12, 18.84);
return c;
}
Show(cyl);
Console.WriteLine();
return 0;
}
}
If you had created a partial class, or you got a partial class from somebody (not as part
of a DLL or nor from another type of library), and you find out that the class is not
complete, you can then complement it. One of the rules you must observe is that the
partial class must have been marked as partial, as we did above. One of the
advantages of partial implementation is that you don't have to get back to the first or
previous file to modify it in order to complement the class. You can simply start another
file and continue the class in it. Two other rules you must observe are that you must use
the same name for the class and you must precede the class keyword with partial.
Here is an example:
Source File: geometry2.cs
using System;
using System;
class Program
{
static Cylinder Initialize()
{
Cylinder c = new Cylinder();
c.Radius = 42.66;
c.Height = 26.48;
return c;
}
Show(cyl);
Console.WriteLine();
return 0;
}
}
Once a partial class has been created, you can create another based on it. The child
class doesn't have to be partial, although it can be.
2. To add a new source file, on the main menu, click Project -> Add New Item...
6. To create a new source file, in the Solution Explorer, right-click Geometry3 -> Add
-> New Item...
7. In the Templates list, make sure Code File is selected; otherwise, click it.
Set the Name to circle2 and click Add
9. To test the class, access the Program.cs file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry3
{
class Program
{
static Circle Initialize()
{
Console.Write("Enter the radius: ");
double rad = double.Parse(Console.ReadLine());
Console.WriteLine("\n==============================");
Console.WriteLine("Circle Characteristics");
Console.WriteLine("------------------------------");
circ.Present();
Console.WriteLine("==============================\n");
return 0;
}
}
}
==============================
Circle Characteristics
------------------------------
C# 3.0 Practical Learning 359
Radius: 10.08
Diameter: 20.16
Circumference: 63.3344544
Area: 319.205650176
==============================
12.To create a new source file, on the main menu, click Project -> Add New Item...
13.In the Templates list, make sure Code File is selected; otherwise, click it.
Set the Name to cylinder1 and press Enter
15.To create a new source file, in the Solution Explorer, right- click Geometry3 -> Add
-> New Item...
16.In the Templates list, make sure Code File is selected; otherwise, click it.
Set the Name to cylindder2 and click Add
18.To test the class, access the Program.cs file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry3
{
class Program
{
static Circle Initialize()
{
Console.Write("Enter the radius: ");
double rad = double.Parse(Console.ReadLine());
return hgt;
}
Console.WriteLine("\n================================");
Console.WriteLine("=//=Cylinder Characteristics=//=");
Console.WriteLine("================================");
Console.WriteLine(" =-= Base Characteristics =-=");
Console.WriteLine("--------------------------------");
circ.Present();
Console.WriteLine("------------------------------");
Console.WriteLine("=-= Volume Characteristics =-=");
cldr.Present();
Console.WriteLine("================================\n");
return 0;
}
}
}
================================
=//=Cylinder Characteristics=//=
================================
=-= Base Characteristics =-=
--------------------------------
Radius: 85.15
Diameter: 170.3
Circumference: 535.012777
Area: 22778.168980775
------------------------------
=-= Volume Characteristics =-=
Height: 44.95
Lateral Area: 24048.82432615
Total Area: 46826.993306925
Volume: 1023879.5605199
================================
Fundamentals of Delegates
Introduction
The C and C++ languages have long used the concept of function pointer. This was
even more useful when programming for the Microsoft Windows operating systems
because the Win32 library relies on the concept of callback functions. Callback functions
are used in Microsoft Windows programming to process messages. For this reason and
because of their functionality, callback functions were carried out in the .NET Framework
but they were defined with the name of delegate.
2. To create a new class, on the main menu, click Project -> Add Class...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WattsALoan1
{
public class LoanEvaluation
{
public double GetPrincipal()
{
Console.Write("Enter the Principal: $");
C# 3.0 Practical Learning 364
double P = double.Parse(Console.ReadLine());
return P;
}
return r;
}
return t;
}
}
}
namespace WattsALoan1
{
public class Program
{
static int Main()
{
int NumberOfPeriods;
double Principal, IntRate;
LoanEvaluation loan = new LoanEvaluation();
Console.WriteLine(
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%");
Console.WriteLine("Loan Processing\n");
Console.WriteLine(
"This program allows you to calculate the amount of money a
");
Console.WriteLine(
"customer will owe at the end of the lifetime of a loan\n");
Principal = loan.GetPrincipal();
IntRate = loan.GetInterestRate();
NumberOfPeriods = loan.GetPeriod();
Console.WriteLine(
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\n");
Console.WriteLine("================================");
Console.WriteLine("Loan Estimation");
C# 3.0 Practical Learning 365
Console.WriteLine("--------------------------------");
Console.WriteLine("Principal: {0:C}", Principal);
Console.WriteLine("Interest: {0:P}", IntRate / 100);
Console.WriteLine("Period: {0} months", NumberOfPeriods);
Console.WriteLine("================================\n");
return 0;
}
}
}
================================
Loan Estimation
--------------------------------
Principal: $14,500.00
Interest: 12.25 %
Period: 48 months
================================
8. In the above program, the clerk was asked to provide the number of months for
the period of the loan. Depending on the loan, one customer may want to specify
the number of days necessary to pay the loan. Another customer may want to pay
a loan over a number of years. To make this possible, we will allow the clerk to
select the type of period for a loan.
Access the LoanProcecssing.cs file and change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WattsALoan1
{
class LoanEvaluation
{
public double GetPrincipal()
{
Console.Write("Enter the Principal: $");
double P = double.Parse(Console.ReadLine());
C# 3.0 Practical Learning 366
return P;
}
return r;
}
if (TypeOfPeriod == 1)
{
Console.Write("Enter the number of days: ");
Periods = int.Parse(Console.ReadLine());
}
else if (TypeOfPeriod == 2)
{
Console.Write("Enter the number of months: ");
Periods = int.Parse(Console.ReadLine());
}
else if (TypeOfPeriod == 3)
{
Console.Write("Enter the number of years: ");
Periods = int.Parse(Console.ReadLine());
}
else
{
TypeOfPeriod = 0;
// The user made an invalid selection. So, we will give
up
Console.WriteLine("Bad Selection\n");
}
}
}
}
namespace WattsALoan1
{
public class Program
{
C# 3.0 Practical Learning 367
static int Main()
{
int Periods = 0;
int TypeOfPeriod = 0;
double Principal, IntRate;
string PeriodName = null;
LoanEvaluation loan = new LoanEvaluation();
Console.WriteLine(
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
Console.WriteLine(
"This program allows you to calculate the amount of money a ");
Console.WriteLine(
"customer will owe at the end of the lifetime of a loan\n");
Console.WriteLine("Loan Processing\n");
Principal = loan.GetPrincipal();
IntRate = loan.GetInterestRate();
if (TypeOfPeriod == 1)
{
PeriodName = "days";
}
else if (TypeOfPeriod == 2)
{
PeriodName = "months";
}
else if (TypeOfPeriod == 3)
{
PeriodName = "years";
}
Console.WriteLine(
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
Console.WriteLine("==================================");
Console.WriteLine("Loan Estimation");
Console.WriteLine("----------------------------------");
Console.WriteLine("Principal: {0:C}", Principal);
Console.WriteLine("Interest: {0:P}", IntRate / 100);
Console.WriteLine("Period: {0} {1}", Periods, PeriodName);
Console.WriteLine("==================================\n");
C# 3.0 Practical Learning 368
return 0;
}
}
}
Loan Processing
Creating a Delegate
To create a delegate, you use the delegate keyword. The basic formula used to create
a delegate is:
[attributes] [modifiers] delegate ReturnType Name ([formal-parameters]);
The modifier can be one or an appropriate combination of the following keywords: new,
public, private, protected, or internal.
The ReturnType can be any of the data types we have used so far. It can also be a type
void or the name of a class.
Because a delegate is some type of a template for a method, you must use parentheses,
required for every method. If this method will not take any argument, leave the
parentheses empty.
C# 3.0 Practical Learning 369
Here is an example:
using System;
After declaring a delegate, it only provides a template for a method, not an actual
method. In order to use it, you must define a method that would carry an assignment to
perform. That method must have the same return type and the same (number of)
argument(s), if any. For example, the above declared delegate is of type void and it
does not take any argument. you can define a corresponding method as follows:
public delegate void Simple();
With such a method implemented, you can associate it to the name of the delegate. To
do that, where you want to use the method, declare a variable of the type of the
delegate and assign the method to the delegate variable. Because you are assigning the
method to a delegate, one of the rules of delegates is that you must not apply the
parentheses to the method. Here is an example
public class Program
{
static int Main()
{
Exercise exo = new Exercise();
return 0;
}
}
Accessing a Delegate
Introduction
Once you have assigned a method to a delegate variable, you can you the delegate
variable as if it were a defined method. That is, you can call as you would a normal
method. Here is an example:
C# 3.0 Practical Learning 370
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Delegates
{
public class Program
{
static int Main()
{
Exercise exo = new Exercise();
msg();
return 0;
}
}
}
In the above example, we had to declare a variable of the (Exercise) class before
accessing the method. An alternative is to create the associated method as static. That
way, you would not need to declare the variable first. Here is an example:
using System;
msg();
return 0;
}
}
An Anonymous Delegate
In the above examples, we had to create a method that would be associated with a
delegate. You can create a delegate, then, when you need to use, create a type of local
implementation of a method and use it. In other words, you do not have to explicitly
define a method prior to using the delegate. Such a method is referred to as anymous.
Before implementing an anonymous method, first declare the delegate you will use:
using System;
To create an anonymous method, declare a variable for the delegate and assign it the
delegate keyword as if it were a method. That is, followed by parentheses and curly
brackets that would represent the body of the method. In the body of the anonymous
method, do whatever you want. Here is an example:
using System;
return 0;
}
}
Once you have done this, you can then call the delegate variable as if it were a normal
method. Here is an example:
using System;
msg();
return 0;
}
}
You can also create an anonymous method using an operator called lambda and
represented by =>. From our example above, to use the lambda operator to create an
anonymous method, omit the delegate keyword and follow the parentheses by the
operator. Here is an example:
using System;
return 0;
}
}
Once you have done this, you can call the delegate variable as a method. Here is an
example:
using System;
msg();
return 0;
}
}
You can create a delegate that returns a value. When creating the delegate, specify the
data type to the left side of the name of the delegate. When defining a method that
would be associated with the delegate, remember that the method must return the
same type of value. In the body of the method, use it as you see fit. Before exiting the
method, make sure you appropriately return a value.
To use the method, follow the same approach as above. This time, when calling the
delegate variable, you should use the parentheses. Here is an example:
using System;
return 0;
}
}
In the same way, you can create an anonymous method that implements the delegate.
To do this, follow the same rule we defined earlier. For example, you can use the
delegate keyword. Here is an example:
using System;
return 0;
}
}
return 0;
}
}
Delegates Compositions
One of the characteristics that set delegates apart from C/C++ function pointers is that
one delegate can be added to another using the + operation. This is referred to as
composition. This is done by adding one delegate variable to another as in a = b + c.
Introduction
If you want to use a method that takes arguments and associate it to a delegate, when
declaring the delegate, provide the necessary argument(s) in its parentheses. Here is an
example of a delegate that takes two arguments (and returns a value):
delegate double Doubler(double x);
When defining the associated method, besides returning the same type of value if not
void, make sure that the method takes the same number of arguments. Here is an
example:
C# 3.0 Practical Learning 375
public class Algebra
{
public static double MultiplyBy2(double a)
{
return a * 2;
}
}
To associate the method to the delegate, you can declare a variable for the delegate
and assign the name of the method to it. Here is an example:
using System;
return 0;
}
}
Notice that only the name of the method is passed to the delegate. To actually use the
delegate, when calling it, add the parentheses to it and in the parentheses, provide a
value for the argument(s). Here is an example:
using System;
return 0;
}
}
A Lambda Expression
You can create an anonymous method for a delegate that takes one or more arguments.
You can do this using the delegate keyword. In its parentheses, pass an argument that
is the same type as the argument of the delegate. Then, in the body of the method, do
what you judge necessary. When calling the variable of the delegate, use the same rules
we have applied so far. Here is an example:
using System;
return 0;
}
}
This technique of using the delegate keyword was introduced in C# 2.0 and has been
updated with the lambda operator. Therefore, this was probably the last time we use it
since we have been able to apply to different types of delegates.
Instead of the delegate keyword, you can define an anonymous method using the
lambda operator. In this case, in the parentheses of the lambda expression, enter the
data type of the argument followed by its name. Here is an example:
using System;
In the body of the anonymous method, use the argument as you see fit. Here is an
example:
using System;
return 0;
}
}
After defining the method, you can call it like a normal method. Here is an example:
using System;
return 0;
}
}
In our example, we specified the type of the argument. If you want, you can let the
compiler figure out the type of argument. In this case, pass only the name of the
argument and not its type. Here is an example:
using System;
return 0;
}
}
A delegate can take more than one argument. To start, when declaring it, pass the
desired number of arguments. If you will use a method to associate to the delegate,
then create the method also. Here is an example:
delegate double Addition(double x, double y);
To use the delegate, follow the techniques we have applied so far and call the delegate
as a method. Here is an example:
using System;
return 0;
}
}
return 0;
}
}
namespace WattsALoan1
{
public class LoanEvaluation
{
public double GetPrincipal()
{
Console.Write("Enter the Principal: $");
double P = double.Parse(Console.ReadLine());
return P;
}
return r;
}
if (TypeOfPeriod == 1)
{
Console.Write("Enter the number of days: ");
Periods = double.Parse(Console.ReadLine());
return Periods / 360;
}
else if (TypeOfPeriod == 2)
{
Console.Write("Enter the number of months: ");
Periods = double.Parse(Console.ReadLine());
return Periods / 12;
}
else if (TypeOfPeriod == 3)
{
Console.Write("Enter the number of years: ");
Periods = double.Parse(Console.ReadLine());
return Periods;
}
else
{
TypeOfPeriod = 0;
// The user made an invalid selection. So, we will give
up
Console.WriteLine("Bad Selection\n");
return 0.00;
}
}
namespace WattsALoan1
{
delegate double Add2Values(double Value1, double Value2);
Console.WriteLine("\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
Console.WriteLine(
"This program allows you to calculate the amount of money a ");
Console.WriteLine(
"customer will owe at the end of the lifetime of a loan\n");
Console.WriteLine("Loan Processing\n");
Principal = loan.GetPrincipal();
IntRate = loan.GetInterestRate();
Period = loan.GetPeriod(ref TypeOfPeriod, ref Periods);
AmountPaidAsInterest =
loan.InterestAmount(Principal, IntRate, Period);
// A lambda expression
Add2Values Add = (double Value1, double Value2) =>
{
return Value1 + Value2;
};
if (TypeOfPeriod == 0)
{
// Since the user made a bad selection, stop the program
here
return 0;
}// Since this "if" condition has a "return 0" line, if the
"if"
// condition produces true, the "return 0" means the function
// would be terminated. If the condition is false, the inside
of
// this "if" condition would not execute and the function
would
// continue. This means that, if the condition is false, then
// the "else' is implied. Therefore, we don't have to write
an
// "else" condition: it is automatic.
if (TypeOfPeriod == 1)
{
PeriodName = "days";
}
else if (TypeOfPeriod == 2)
{
PeriodName = "months";
}
else if (TypeOfPeriod == 3)
{
PeriodName = "years";
}
Console.WriteLine("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
Console.WriteLine("==================================");
Console.WriteLine("Estimate on loan");
Console.WriteLine("----------------------------------");
Console.WriteLine("Principal: {0:C}", Principal);
C# 3.0 Practical Learning 382
Console.WriteLine("Interest: {0:P}", IntRate / 100);
Console.WriteLine("Period: {0} {1}", Periods, PeriodName);
Console.WriteLine("--------------------------------");
Console.WriteLine("Total Amount Paid: {0:C}", Add);
Console.WriteLine("Interest paid on Loan: {0:C}",
AmountPaidAsInterest);
Console.WriteLine("==================================\n");
return 0;
}
}
}
Loan Processing
==================================
Estimate on loan
----------------------------------
Principal: $12,500.00
Interest: 10.55 %
Period: 42 months
--------------------------------
Total Amount Paid: $17,115.63
Interest paid on Loan: $4,615.63
==================================
Using delegates, one method can be indirectly passed as argument to another method.
To proceed, first declare the necessary delegate. Here is a example of such a delegate:
public delegate double Squared(double x);
After declaring a delegate, remember to define a method that implements the needed
behavior of that delegate. You can define the associated method in a class other than
the one where the delegate would be used. Here is an example:
using System;
You can also define the method in the class where the delegate would be needed. Once
the method that implements the delegate is known, you can use the delegate as you see
fit. To do that, you can declare a variable of the type of that delegate and assign it to
the variable. Here is an example:
using System;
return 0;
}
}
This declaration gives life to the delegate and can then be used as we have proceed
with delegates so far. Here is an example:
using System;
return 0;
}
}
In the same way, you can use a lambda expression to implement an anonymous method
that would be associated with a delegate. Here is an example:
using System;
return 0;
}
}
Introduction
C# 3.0 Practical Learning 386
So far, we have learned how to create and use delegate of primitive types. We learned
how to create a void delegate, how to create a delegate that returns a value, and how
to create a delegate that takes one or more argument. Just as a reminder, here is an
example:
using System;
public Cube()
{
_side = 0;
}
public Cube(double s)
{
_side = s;
}
Console.WriteLine("Cube Characteristics");
Console.WriteLine("Side: {0}", SmallBox.Side);
Console.WriteLine("Area: {0}", AreaDefinition);
Console.WriteLine("Volume: {0}\n", VolDefinition);
return 0;
}
}
A delegate can be created to return a value that is of a class type. Of course you must
know the class you want to use because the compiler would like to know the type of
value that the delegate would return. You can use one of the many built-in classes of
the .NET Framework or you can create your own class. When creating the delegate,
specify the name of the class to its left as the returned type of value. Here is an
example:
delegate Person Creator();
After doing this, you can create a method that implements the delegate. The method
must return the same type of value as the delegate. Here is an example:
using System;
To use the delegate, declare a variable for it and assign the method to it. Here is an
example:
using System;
return 0;
}
}
You can then call use the variable as you see fit. Instead of explicitly creating a method
that implements the delegate, you can create an anonymous method using a lambda
expression. In the body of the anonymous method, make sure you return a value of the
type of the delegate. Here is an example:
using System;
PersonalInformation.FirstName = "Julius";
PersonalInformation.LastName = "Krands";
return PersonalInformation;
};
Create();
return 0;
}
}
To use the delegate, you can first create a method that implements the delegate, then
declare a variable for the delegate and assign the method to it. If you prefer to create
an anonymous method using a lambda expression, in the parentheses, enter a name for
the argument and use that argument in the body of the method as you see fit. Here is
an example:
public class Exercise
{
static int Main()
{
Anchor personal = (individual) =>
{
Console.WriteLine("=//= Personal Information =//=");
Console.WriteLine("First Name: {0}", sample.FirstName);
Console.WriteLine("Last Name: {0}", sample.LastName);
};
return 0;
}
}
You can then call the method as you see fit. Here is an example:
using System;
Create();
personal(PersonalInformation);
return 0;
}
}
You can create a delegate that takes a class as argument and returns a class type
You can create a delegate that takes more than one argument. One of the
arguments could be a class type and the other(s) a class or a primitive type
Events
Introduction
Except for the main class of your program (the class that contains the Main() method),
every class is mostly meant to interact with other, either to request values and methods
of the other classes or to provide other classes with some values or a behavior they
need. When a class A requests a value or service from another class B, class A is
referred to as a client of class B. This relationship is important not simply because it
establishes a relationship between both classes but also because class B should be ready
to provide the value or behavior that a client needs at a certain time.
While a class B is asked to provide some values or methods to another class A, many
things would happen. In fact, there is an order that things should follow. For example,
during the lifetime of a program, that is, while a program is running, a class may be
holding a value it can provide to its client but at another time, that value may not be
available anymore, for any reason; nothing strange, this is just the ways it happens.
Because different things can happen to a class B while a program is running, and
because only class B would be aware of these, it must be able to signal to the other
classes when there is a change. This is the basis of events: An event is an action that
occurs on an object and affects it in a way that its clients must be made aware of.
Events are mostly familiar to those who do graphical (GUI) programming as they are
able to "visually" work on Windows controls and as they are able to access the objects
C# 3.0 Practical Learning 391
on which actions are happening and the objects that must know when these actions
occur. Still, because events are dealt with in C#, you should be aware of their
functionality.
Although events are mostly used in Windows controls programming, they can also be
implemented in console applications.
Event Creation
class Exercise
{
public static void Welcome()
{
Console.WriteLine("Welcome to the Wonderful World of C#
Programming!");
}
}
To actually declare an event, you use the event keyword with the following formula:
[attributes] [modifiers] event type declarator;
[attributes] [modifiers] event type member-name {accessor-declarations};
The modifier can be one or a combination of the following keywords: public, private,
protected, internal, abstract, new, override, static, virtual, or extern.
The event keyword is required. It is followed by the name of the delegate that specifies
its behavior. If the event is declared in the main class, it should be made static. Like
everything in a program, an event must have a name. This would allow the clients to
know what (particular) event occurred. Here is an example:
using System;
class Exercise
{
public static event dlgSimple Simply;
class Exercise
{
public static event dlgSimple Simply;
When the event occurs, its delegate would be invoked. This specification is also referred
to as hooking up an event. As the event occurs (or fires), the method that implements
the delegate runs. This provides complete functionality for the event and makes the
event ready to be used. Before using an event, you must combine it to the method that
implements it. This can be done by passing the name of the method to the appropriate
delegate, as we learned when studying delegates. You can then assign this variable to
the event's name using the += operator. Once this is done, you can call the event. Here
is an example:
using System;
class Exercise
{
public static event dlgSimple Simply;
SayHello();
return 0;
}
C# 3.0 Practical Learning 393
}
Instead of the += operator used when initializing the event, you can implement add and
remove of the event class. Here is an example:
using System;
class Exercise
{
public event dlgSimple Simply
{
add
{
Simply += new dlgSimple(Welcome);
}
remove
{
Simply -= new dlgSimple(Welcome);
}
}
Fundamentals of Structures
Introduction
A structure is an enhanced version of the primitive data types we have used in previous
lessons. Like a class, a structure is created from one variable of a primitive type or by
combining various variables of primitive types.
To create a structure, you use the same formula as for a class but with the struct
keyword. Here is an example of a structure:
struct Integer
{
}
Like a class, a structure can have fields. They are listed in the body of the structure.
Here is an example:
struct Integer
{
private int val;
}
Structure Declaration
Like any other data type, to use a structure, you can first declare a variable from it. To
allocation memory for a variable declared from a structure, use the new operator as
done for a class. Here is an example:
using System;
struct Integer
{
private int val;
class Program
{
static int Main()
{
Integer Natural = new Integer();
return 0;
}
}
As done for variables of the other types and as seen for classes, to declare a variable for
a structure, you can use the var keyword. After declaring the variable, you can use the
object the same way you would a class. You can access its members (fields, properties,
and methods) using the period operator. Here is an example:
using System;
struct Integer
{
private int val;
class Program
{
static int Main()
{
var Natural = new Integer();
Although there are many similarities in the behaviors of classes and structures, you
should use a structure when the object you are creating is meant to represent relatively
small values. Like primitive data types and unlike a class, a structure is a value type.
A Structure as a Property
Once a structure exists, you can use it like a data type. For example, you can create a
property that is a structure type. The rules are the same we reviewed for creating a
property of a class. After creating the property, you can use it as you see fit. Here is an
example:
using System;
Rect.CreateRectangle();
Console.WriteLine();
Console.WriteLine("Rectangle Characteristics");
Console.WriteLine("Length: {0}", Rect.Length.Value);
Console.WriteLine("Height: {0}", Rect.Height.Value);
Console.WriteLine("Perimeter: {0}",
(Rect.Length.Value + Rect.Height.Value) * 2);
Console.WriteLine("Area: {0}",
Rect.Length.Value * Rect.Height.Value);
return 0;
}
}
Rectangle Characteristics
Length: 44.84
Height: 26.75
Perimeter: 143.18
Area: 1199.47
Press any key to continue . . .
Like regular data type or a class, a structure can serve as the return type of a method.
The rules are more related to those of a class. When creating the method, type the
name of the structure on the left side of the name of the method. In the body of the
method, implement the desired behavior. Before exiting the method, make sure you
return a valid value that is of the type of the structure. When a method returns a value
of the type of a structure, you can assign the method to a variable of the type of the
structure.
Rect.CreateRectangle();
Console.WriteLine();
Console.WriteLine("Rectangle Characteristics");
Console.WriteLine("Length: {0}", Rect.Length.Value);
Console.WriteLine("Height: {0}", Rect.Height.Value);
Console.WriteLine("Perimeter: {0}",
(Rect.Length.Value + Rect.Height.Value) * 2);
Console.WriteLine("Area: {0}",
Rect.Length.Value * Rect.Height.Value);
return 0;
}
}
Rectangle Characteristics
Length: 36.04
Height: 22.86
Perimeter: 117.8
Area: 823.8744
Press any key to continue . . .
Like a data type, a structure can be passed as argument to a method. The argument is
primarily passed as done for a class. After passing the argument, in the body of the
Console.WriteLine();
ShowCharacteristics(Rect);
return 0;
}
}
Rectangle Characteristics
Length: 114.55
Height: 82.72
Perimeter: 394.54
Area: 9475.576
Press any key to continue . . .
rect.CreateRectangle();
Console.WriteLine();
Console.WriteLine("Rectangle Characteristics");
Console.WriteLine("Length: {0}", rect.Length.Value);
Console.WriteLine("Height: {0}", rect.Height.Value);
Console.WriteLine("Perimeter: {0}",
(rect.Length.Value + rect.Height.Value) * 2);
Console.WriteLine("Area: {0}",
rect.Length.Value * rect.Height.Value);
Rectangle Characteristics
Length: 75.82
Height: 55.64
Perimeter: 262.92
Area: 4218.6248
Press any key to continue . . .
Introduction
The C# language (actually the .NET Framework) treats each primitive data type as a
class. In fact, each data type was created as a structure. Some characteristics are
common to many of these structures while some other aspects are unique to some
others.
To support the routine operations of regular variables, each structure that represents a
primitive type is equipped with some member variables and methods.
Conversion to a String
With a value of a primitive type, at one time or another, you may need to convert the
value of a variable from its type to a string. To support this, each structure of a
primitive type is equipped with a method named ToString. This method is overloaded
with various versions. One of the versions of this method takes no argument. The syntax
of this method is:
public override string ToString();
Another version of this method takes as argument a string. This string holds an
expression used to format the value of the variable that called the method. The syntax
of this method is:
public string ToString(string format);
You can pass the desired string to format the value to be displayed.
Parsing a String
In Lesson 5, we saw how to retrieve a value from the console and convert it to the
desired value. To support this operation, each structure of a primitive data type is
equipped with a static method named Parse. The syntaxes of this method are:
sbyte
short
class Program
{
static int Main()
{
double value = 0;
return 0;
}
}
byte
sbyte
short
When calling this method, if a bad value is passed to the Parse() method, for example
if the user enters an invalid value to a double.Parse(Console.ReadLine()) call, the
program produces an error (in Lesson 17, we will learn that the program throws an
exception). To assist you with this type of problem, each structure of a primitive type is
equipped with a method named TryParse. This method is overloaded with two versions
that each returns a bool. One of the versions of this method takes two arguments: a
string and a variable passed as an out reference. The syntaxes of this method are:
byte
sbyte
short
Based on this, if a double variable calls this method, the first argument is passed a
string and the second argument is passed as an out double. This means that the
second argument is returned from the method also.
If the first argument passed to the method is valid, the method returns two values:
true and the entered value is stored in the out argument
If the value of the first argument is invalid, the method returns false and the
default value of the data type is stored in the out argument. For example, if the
variable that called the method is on type int but the user entered the wrong
value, the method returns two values: false and 0 (because 0 is the default value
of an int. If the variable that called the method is on type char but the user
entered a bad value, the method returns two values: false and an empty
character (because the default value of a char is empty).
Notice that the compiler didn't produce (throw) an error (an exception).
In Lesson 1, we saw that, when you declare a variable, the compiler reserves an amount
of memory space preparing to store its value. As different variables have different
requirements, some of them use less or more memory than others. When you declare a
variable, the data type you specify allows the compiler to know how mush space would
be needed to store the value of that variable. There is a minimum and a maximum
values that can be stored in the memory space reserved for a variable. Based on this, a
To help you find out the minimum value that a data type can hold, each structure of a
primitive type is equipped with a constant member named MinValue. In the same way,
the maximum value that a data type can support is represented by a constant field
named MaxValue. You can check these minimum and maximum with the following
program:
using System;
class Program
{
static int Main()
{
Console.WriteLine(
"=================================================================
======");
Console.WriteLine("C# Type .NET Structure Minimum
Maximum");
Console.WriteLine(
"=================================================================
======");
Console.WriteLine("char Char {0}\t\t\t{1}",
char.MinValue, char.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("byte Byte {0}\t\t\t{1}",
byte.MinValue, byte.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("sbyte SByte {0}\t\t\t{1}",
sbyte.MinValue, sbyte.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("short Int16 {0}\t\t\t{1}",
short.MinValue, short.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("ushort UInt16 {0}\t\t\t{1}",
UInt16.MinValue, UInt16.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("int Int32 {0}\t\t{1}",
int.MinValue, int.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("uint UInt32 {0}\t\t\t{1}",
UInt32.MinValue, UInt32.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("long Int64 {0}\t{1}",
C# 3.0 Practical Learning 408
long.MinValue, long.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("uint64 UInt64 {0}\t\t\t{1}",
UInt64.MinValue, UInt64.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("float Single {0}\t\t{1}",
float.MinValue, float.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("double Double {0}\t{1}",|
double.MinValue, double.MaxValue);
Console.WriteLine(
"-----------------------------------------------------------------
------");
Console.WriteLine("decimal Decimal {0} {1}",
decimal.MinValue, decimal.MaxValue);
Console.WriteLine(
"=============================================================");
return 0;
}
}
One of the most common operations performed on variables consists of comparing their
values: to find out whether they are equal or to know whether one is higher than the
other. These operations can be performed using the Boolean operators we reviewed in
Lesson 8. The Boolean operations are part of the C# language. To formally implement
them, each structure of a data type is equipped with a method named CompareTo that
is overloaded with two versions.
byte
sbyte
short
The method returns an int value. For example, imagine you have two int variables
named Variable1 and Variable2, you can call the CompareTo() method of the first
variable to compare its value to that of the second variable. This would be done as in:
int result = Variable1.CompareTo(Variable2);
If the value of Variable1 is greater than the value of Variable2, the method returns
1
C# 3.0 Practical Learning 410
If the value of Variable1 is less than the value of Variable2, the method returns -1
Here is an example:
using System;
class Program
{
static int Main()
{
int Variable1 = 248;
int Variable2 = 72937;
int result = Variable1.CompareTo(Variable2);
Console.WriteLine("{0} compared to {1} produces {2}",
Variable1, Variable2, result);
return 0;
}
}
Another version of the CompareTo() method allows you to compare the value of a
variable with a variable whose type is not the same as the variable that called it. Since
all types and classes of C# are based on object, this second version takes as argument
an object object. The method return an int value. The syntax of this version is:
public int CompareTo(object value);
Notice that you can use the CompareTo() method to test for equality. Another method
used to check the equality of two variables is the Equals() method. The Equals()
method is overloaded in two versions and each takes one argument. The Equals()
method returns a Boolean value. One of the versions of this method takes as argument
a value of the same type as the variable that called it. The syntaxes of this version are:
byte
sbyte
short
The method compares the values of the variable that called it and the argument, as in
bool result = Variable1.Equals(Variable2);
If the value of the first variable is the same as that of the second variable, the
method returns true
If the values of the variables are different, the method returns false
Here is an example:
using System;
class Program
{
static int Main()
{
int Variable1 = 1407;
int Variable2= 59266;
bool result = value1.Equals(value2);
Console.WriteLine("{0} = {1} produces {2}",
Variable1, Variable2, result);
return 0;
}
}
The other version of the Equals() method takes as argument an object value. The
syntax of this version is:
public override bool Equals(object obj);
Here is an example:
using System;
class Program
{
static int Main()
return 0;
}
}
Introduction
As seen in previous lessons, the bool data type is used to represent a value considered
as being true or false. In the .NET Framework, the bool data type is represented by the
Boolean structure. The true value of a bool variable is represented by the TrueString
field and the false value is represented by the FalseString member variable. In other
words, when true (or false) is represented as a string, "true" (or "false"” is the
same as TrueString (or FalseString).
We saw in a Lesson 8 that you could retrieve the value of a Boolean variable from a
user. To support this, the Boolean structure is equipped with a static method named
Parse. The Boolean.Parse() method is declared as follows:
This method takes as argument a string. The argument must contain either the word
True (case-insensitive) or the word False. If the argument is passed as "True", the
method returns true. If the argument is "false", this method returns false. Here is
an example:
using System;
class Program
{
static int Main()
{
bool result = bool.Parse("TRUE");
When calling the Boolean.Parse() method to retrieve the value of a Boolean variable,
if the supplied value is "TRUE" or "FALSE", the compiler would process it. If the value is
not valid, the program would produce an error. Here is an example:
using System;
class Program
{
static int Main()
{
bool HouseHas3Bedrooms = bool.Parse("ItHas3Bedrooms");
To avoid the error, the Boolean structure provides the TryParse() method. Its syntax
is:
public static bool TryParse(string value, out bool result);
The first argument is the value to be parsed. If that value is valid, the second argument
holds the True or False value of the first. Here is an example:
using System;
class Program
{
static int Main()
{
bool alt;
bool HouseHas3Bedrooms = bool.TryParse("True", out alt);
class Program
{
static int Main()
{
bool alt;
Notice that the first argument returns True although it was passed as False. This means
that, if the value of the first argument is valid, it is the second argument, not the first,
that holds the result. If the first argument is not valid, the second argument returns a
False value. Consider the following version of the program:
using System;
class Program
{
static int Main()
{
bool alt;
bool HouseHas3Bedrooms = bool.TryParse("Don't Know", out alt);
In C#, to compare the values of two Boolean variables for equality, you can use the
equality operator "==". Here is an example:
using System;
class Program
{
static int Main()
{
bool House1Has3Bedrooms = true;
bool House2Has3Bedrooms = false;
To support this comparison, the Boolean structure of the .NET Framework is equipped
with the Equals() method. Its syntax is:
public bool Equals(bool obj);
This method takes one argument as the Boolean value or variable to be compared to the
variable that called it. Here is an example of calling it:
using System;
class Program
{
static int Main()
{
bool House1Has3Bedrooms = false;
bool House2Has3Bedrooms = false;
The Equals() method can easily be called by one Boolean variable that receives
another Boolean variable as argument. If you don't know the exact type of value of the
argument, you can still pass it an object value. To support this, the Equals() method
has another version whose syntax is:
public override bool Equals(Object obj);
If the type of variable is not necessarily a Boolean type, you can pass it as an object
value. To do this, you can use the other version of the CompareTo() method. Its syntax
is:
public int CompareTo(Object obj);
Floating-Point Numbers
Introduction
As seen in Lesson 2, to support floating-point numbers, you can use the float, the
double, or the decimal data types. The C# float data type originates from the Single
structure of the .NET Framework. The double data type is based on the Double structure
of the .NET Framework. The C# decimal data type is type-defined from the .NET
Framework’s Decimal structure. To declare a floating-point variable, you can use one of
these data types and initialize it.
When initializing a floating-point variable, you should make sure you assign it a value
that can fit in the memory allocated for it. As mentioned for the integer data types, the
minimum value that a float variable can hold is represented by the MinValue constant
of the Single structure and the MinValue field of the Double. The maximum value that a
float or a double variable can hold is named MaxValue.
After declaring and initializing a float or a double variable, it should hold an appropriate
value. If you get the variable’s value some other way, at one time or another, you may
not know what value is stored in the memory allocated for the variable. In fact, the
variable may hold a value that is not a number. To check whether the variable is holding
a value that is not a number, you can access its NaN constant. To do this, type the float
or double data type, followed by the period operator, and followed by the NaN constant.
Here is an example:
using System;
class Program
{
static int Main()
{
double number = 0D;
Using one integer and one floating-point number, or with two floating-point numbers,
you can perform one of the routine arithmetic operations such as the addition, the
subtraction, the multiplication, or the division. When it comes to the division and if
performed on two constants, you can get a positive or a negative number. In highly
precise calculations, you may have to deal with an approximate number whose exact
value is not known. For example, the smallest positive number is called epsilon. In the
Double and the Single structures, this constant is named Epsilon. For the single-
precision type, the epsilon is equal to 1.445. For a double-precision type, the epsilon
constant is equivalent to 4.94065645841247-324. As you can see, this number is
extremely low.
When dealing with real numbers, some operations produce very little or very large
numbers. In algebra, the smallest number is called negative infinity. In the .NET
Framework, the negative infinity is represented by a constant named
NegativeInfinity. To access this number, type either float or double, followed by a
period operator, followed by the name of this constant. Here is an example:
using System;
class Program
{
static int Main()
{
Console.WriteLine("Negative Infinity = {0}",
double.NegativeInfinity);
return 0;
}
}
To find out if a variable holds a negative infinity value, you can call the
IsNegativeInfinity() method from the variable. The syntaxes of this method are:
On the other extreme, the possible largest number is named positive infinity. This
constant is represented in the .NET Framework by the PositiveInfinity value. To
access this constant, type float or double, followed by the period, followed by the name
of this constant. To find out if a variable’s value is a positive infinity, you can call its
IsPositiveInfinity() method. The syntaxes of this method are:
To check whether the value of a variable is one of the infinities, you can call its
IsInfinity() method. The syntaxes of this method are:
class Program
{
static int Main()
{
double number1 = 22.15D;
double number2 = 22.15D;
For the sake of discussion, these values of these variables were limited to 2 decimal
places. If they represented hourly salaries of employees, the comparison would be easily
performed and can produce an exact result. If you want to apply more precision do the
numbers, for example if the variables represent weight values, you would need more
places on the right side of the decimal separator. Consider the following program:
using System;
class Program
{
static int Main()
{
double number1 = 22.156D;
double number2 = 22.157D;
This time, because of more precision, the variables don’t hold the same value.
Besides the equality, you can also compare floating-point variables to find out if one has
a value lower than the other. To support such operations, the Single and the Double
Introduction
C# was clearly created to improve on C++ and possibly offer a new alternative. To
achieve this goal, Microsoft created a huge library to accompany the language.
The .NET Framework is a huge library made of various classes and constants you can
directly use in your C# application without necessarily explicitly loading an external
library. To start, this main library of C# provides a class called Object.
As you may have realized by now, every variable or function in C# (as in Java) must
belong to a class, unlike C/C++ where you can have global variables or functions.
Therefore, you always have to create at least one class for your application. As such,
when you create a class, it automatically inherits its primary characteristics from the
parent of all classes: Object.
2. To create a new class, in the Solution Explorer, right-click Sport1 -> Add -> Class...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Sport1
{
class Sport
{
private double _ballWeight;
private int _players;
private double _courtLength;
private double _courtWidth;
namespace Sport1
{
class Program
{
static int Main()
{
Sport tennis = new Sport();
Console.WriteLine("Sport Characteristics");
Console.WriteLine("Ball Weight: {0} grams",
tennis.BallWeight);
Console.WriteLine("Players on each side: {0}",
tennis.NumberOfPlayers);
Console.WriteLine("Court Dimensions(LxW): {0}m X {1}m\n",
tennis.CourtLength, tennis.CourtWidth);
return 0;
}
}
}
When you declare and initialize two variables, one of the operations you may want to
subsequently perform is to compare their value. To support this operation, the Object
class provides its children with a method called Equals. The Equals() method comes in
two versions. The first has the following syntax:
public virtual bool Equals(object obj);
This version allows you to call the Equals() method on a declared variable and pass the
other variable as argument. Here is an example:
using System;
class BookCollection
{
static void Main()
{
// First book
int NumberOfPages1 = 422;
// Second book
int NumberOfPages2 = 858;
// Third book
int NumberOfPages3 = 422;
As a static method, to use it, you can pass the variables of the two classes whose
values you want to compare.
In both cases, if the values of the variables are similar, the Equals() method returns
true. If they are different, the method returns false. If you are using the Equals()
method to compare the variables of two primitive types, the comparison should be
straight forward. If you want to use this methods on variables declared from your own
class, you should provide your own implementation of this method.
2. To create your own implementation of the Equals() method, change the file as
follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Sport1
{
class Sport
{
. . .
return false;
}
}
}
namespace Sport1
{
class Program
{
static int Main()
{
Sport Euro2002 = new Sport();
Sport CAN2004 = new Sport();
Sport tennis = new Sport();
if (CAN2004.Equals(tennis) == true)
Console.WriteLine("The CAN2004 and the tennis variables are
equal");
else
Console.WriteLine("The Euro2002 and the tennis variables are not
equal");
if (Euro2002.Equals(CAN2004) == true)
Console.WriteLine("The Euro2002 and CAN2004 variables are
equal");
else
Console.WriteLine("The Euro2002 and CAN2004 variables are not
equal");
return 0;
}
}
}
Stringing a Class
class BookCollection
{
static int Main()
{
int NumberOfPages = 422;
Although the Object class provides this method as non abstract, its implemented
version is more useful if you use a primitive type such as int, double and their variances
or a string variable. The best way to rely on it consists of overriding it in your own class
if you desired to use its role.
namespace Sport1
{
class Sport
{
private double _ballWeight;
private int _players;
private double _courtLength;
private double _courtWidth;
return false;
}
if (NumberOfPlayers.Equals(1))
person = " person";
else
person = " persons";
string result =
"\nBall Weight: " + BallWeight + " grams" +
"\nPlayers on each side: " + NumberOfPlayers + person +
"\nCourt Dimensions(LxW): " +
CourtLength + "m X " + CourtWidth + "m";
return result;
}
}
}
Console.WriteLine("====================================");
Console.WriteLine("Cup Game Characteristics");
Console.Write("------------------------------------");
Console.WriteLine(CAN2004);
Console.WriteLine("\n====================================");
return 0;
}
}
}
====================================
Tennis Game Characteristics
------------------------------------
Ball Weight: 57.5 grams
Players on each side: 1 person
Court Dimensions(LxW): 23.7m X 8.23m
====================================
Press any key to continue . . .
class Exercise
{
static void Main()
{
object Number = 244;
object Thing = "Professor Kabba";
Console.WriteLine(Number);
Console.WriteLine(Thing);
}
}
As you can see, when an object variable is initialized, the compiler finds out the type of
value that was assigned to it. This is referred to as boxing. This mechanism is
transparently done in C# (and in Visual Basic but not in Visual C++ 2003 (it is possible
that something will be done in the next version, or not)).
If you declare a variable using a primitive data type ( int, float, double, etc), at one
time, you may be interested in converting the value of that variable into an object.
Here is an example:
using System;
class Exercise
{
static int Main()
{
int Number = 244;
object Thing = Number;
Console.WriteLine(Number);
Console.WriteLine(Thing);
return 0;
}
}
This operation is referred to as unboxing. As you can see, this operation is performed
transparently (Visual C++ 2003 doesn't do it transparently).
Boxing and unboxing make C# a very flexible and wonderful language (if you misuse it,
of course it can be dangerous).
While a constructor, created for each class, is used to instantiate a class. The Object
class provides the Finalize() method as a type of destructor.
The System namespace provides one of the largest definition of classes of the .NET
Framework, but it doesn't contain everything. For example, when you start writing
graphical user interface (GUI) applications, you will have to use other namespaces. The
namespaces are contained in libraries called assemblies. The actual classes used in
various applications are created and defined in these libraries. Before using a class, you
must know the name of the assembly in which it is defined. You must also know the
name of its namespace. These three pieces of information, the name of the class, the
namespace in which it is defined, and the name of the assembly in which the
namespace is contained, are very important. Because there are so many classes,
namespaces, and libraries, the MSDN documentation is your best reference. We can
only mention a few, especially those that are relevant for the subjects we are reviewing.
Random numbers
Introduction
Imagine you have a series of numbers, such these: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, and 20. Imagine you want to select one of these numbers,
any of them. A number is referred to as random if it has been selected from a pool
without a specific pattern to follow. For example, if you decide to select the value 17
from this list, if there was an exact reason that number was selected, then it is not
considered random. In reality, it is difficult for a number to qualify as random. For this
reason, most random numbers are referred to as pseudo-random.
To support the ability to create or choose a random number, the .NET Framework
provides the Random class. To start, you can declare a variable of this class, using one
of its two constructors. Here is an example that uses the default constructor:
using System;
class Program
{
static int Main()
{
Random rndNumber = new Random();
return 0;
}
}
This method generates a randomly selected integer between 0 and the MinValue value
of the int data type. Here is an example:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random();
int rndNumber = rndNumbers.Next();
return 0;
}
}
In the same way, you can call this version of the Next() method repeatedly to get
random. Here is an example:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random();
int rndNumber = 0;
return 0;
}
}
class Program
{
static int Main()
{
Random rndNumbers = new Random();
int rndNumber = rndNumbers.Next();
return 0;
}
}
Notice that the numbers generated are different. When creating a program that
repeatedly gets a series of random numbers, you may (or may not) want the Random
class to generate the same number over and over again. A seed is a constant value that
controls whether a random generation would produce the same result every time it
occurs. For example, using a seed, you can impose it upon the Random class to
generate the same number every time the Next() method is called. To support the ability
to use a seed, the Random class is equipped with a second constructor whose syntax is:
public Random(int Seed);
Based on this, to specify a seed, when declaring a Random variable, pass a constant
integer to the constructor. Here is an example:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random(20);
int rndNumber = rndNumbers.Next();
return 0;
}
}
C# 3.0 Practical Learning 432
Here is one example of running the program:
Number: 375271809
Press any key to continue . . .
Notice that the numbers are the same. Consider this program also:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random(20);
int rndNumber = 0;
return 0;
}
}
Notice that the sequences are the same. In both cases, this indicates that, if you specify
a seed, the Random class would generate the same number or the same sequence of
numbers.
So far, we have been using with any number that would fit an integer. In some
assignments, you may want to restrict the range of numbers that can be extracted.
Fortunately, the Random class allows this. Using the Random class, you can generate
random positive numbers up to a maximum of your choice. To support this, the Random
class is equipped with another version of the Next() method whose syntax is:
C# 3.0 Practical Learning 433
public virtual int Next(int maxValue);
The argument to pass to the method determines the highest integer that can be
generated by the Next() method. The method returns an integer. Here is an example
that generates radom numbers from 0 to 20:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random();
int rndNumber = 0;
return 0;
}
}
The above version of the Next() method generates numbers starting at 0. If you want,
you can specify the minimum and the maximum range of numbers that the Next()
method must work with. To support this, the Random class is equipped with one more
version of this method and that takes two arguments. Its syntax is:
public virtual int Next(int minValue, int maxValue);
The first argument specifies the lowest value that can come from the range. The second
argument holds the highest value that the Next() method can generate. Therefore, the
method would operate between both values. Here is an example that generates random
numbers from 6 to 18:
using System;
class Program
{
static int Main()
{
Random rndNumbers = new Random();
int rndNumber = 0;
return 0;
}
}
One of the strengths of Visual Basic, from its beginning, was its huge library of
functions. Unfortunately, even when Visual Basic was part of the Visual Studio 6.0
environment, its functions belonged only to it and to its child languages such as VBA
and VBScript. When Visual Studio .NET was created, the developers of Visual Basic
added all of its valuable functions and in fact made them available to the other
languages that use the .NET Framework. This means that those wonderful functions are
available to use in your C# programs.
The functions of Microsoft Visual Basic still belong to it and they can be called
transparently in a Visual Basic application. If you want to use them in a non-Visual Basic
application, you must remember to reference its library. Most (if not all) of the functions
of Visual Basic are created in the Microsoft.VisualBasic.dll assembly but they
might be in different namespaces. Based on this, you can include any Visual Basic
function in your program. Here is an example:
Source File: Exercise.cs
using System;
class Exercise
{
static void Main()
{
double Number;
double Result;
if( !Microsoft.VisualBasic.Information.IsNumeric(strNbr) )
Number = 0.00;
else
Number = Microsoft.VisualBasic.Conversion.Val(strNbr);
Result = Number * 2;
When compiling the program, you must reference the Microsoft.VisualBasic.dll library.
Here is an example:
csc /reference:Microsoft.VisualBasic.dll Exercise.cs
C# Custom Libraries
Introduction
If the .NET Framework doesn't have a class you are looking for, you can create one and
be able to use it over and over again in different programs. You can even create a
commercial class and be able to distribute or sell it. To make this possible, you can
"package" one or more classes in a library. A library is a program that contains classes
and/or other resources that other programs can use. Such a program is created with the
same approach as the programs we have done so far. Because a library is not an
executable, it doesn't need the Main() function. A library usually has the extension .dll.
Creating a Library
A library can be made of a single file or as many files as necessary. A file that is part of
a library can contain one or more classes. Each class should implement a behavior that
can eventually be useful and accessible to other classes. The classes in a library are
created exactly like those we have used so far. Everything depends on how you compile
it.
To create a library, start by typing its code in a text file. Once the library is ready, to
compile it, at the Command Prompt, you would type:
csc /target:library NameOfFile.cs
and press Enter. After doing this, a library with the name of the file and the extension
.dll would be created. If you want a custom name, use the following syntax:
csc /target:library /out:DesiredNameOfLibrary.dll NameOfFile.cs
1. To start a new project, on the main menu, click File -> New Project...
C# 3.0 Practical Learning 436
2. In the New Project dialog box, click Class Library
namespace Operations1
{
public class Operations
{
public static double Addition(double x, double y)
{
return x + y;
}
7. To save the project, on the Standard toolbar, click the Save All button
12.To create the library, on the main menu, click Build -> Build Solution
13.To start another project, on the main menu, click File -> New Project...
16.In the Solution Explorer, right-click References and click Add Reference...
18.In the list of folders, double-click Operations1 and locate the Operations1.dll file (it
should be in the Release (or the Debug) sub-folder of the bin folder)
20.Click OK.
In the Solution Explorer, expand the References node if necessary and make sure
that there is a new node labeled Operations1
namespace Algebra1
{
class Program
{
static int Main()
{
double Number1 = 244.58;
double Number2 = 5082.88;
double Result =
Operations1.Operations.Addition(Number1, Number2);
One of the most important sought goals in .NET is to allow different languages to
collaborate, such as sharing code. One way this can happen is to be able to use the
functionality of one language into another. As an illustration, we saw earlier that you
could use the rich library of Visual Basic functions in a C# application. As no library is
ever complete, you may still need functionality that is not easily found. Furthermore, you
may be working with a team of C++ programmers who have already created a set of
functions or complex operations. You should be able to use that existing code.
Creating a Library
#pragma once
namespace Business {
Once the project is ready, you must build it (on the main menu, Build -> Build
Business). As a result, the compiler would create a file with the .dll extension:
Creating a library in C++ is easy. To use it, there are a few rules you must follow. To
start, you must make sure that your project can "physically" find the library. Probably
the easiest way to take care of this is to copy the dll file and paste it in the folder that
contains your project's executable. You can also do this directly in Visual Studio by
importing the library file as we saw earlier.
namespace DepartmentStore
{
class Exercise
{
[DllImport("Business.dll")]
public static extern double CalculateDiscount(double price,
double discount)
return 0;
}
}
}
This makes your library code ready to be used, which you can do as you would any
other code. This means that you can compile your program the way we did in the
previous section.
The Microsoft Windows operating system was originally written in C, the parent
language of C++ and C# (also of Java and JavaScript). To allow programmers to create
applications, Microsoft released a library called Win32. This is a series of functions and
classes, etc, that you previously had to use. As time has changed, you don't need to
exclusively use Win32 anymore to create a Windows application. Nonetheless, Win32 is
still everywhere and it is not completely avoidable because many or some of the actions
you would want to perform in a Windows application are still available only in Win32.
Fortunately, in most cases, it is not always difficult to use some of these functions in a
C# applications, as long as you observe some rules. Here is an example:
using System;
using System.Runtime.InteropServices;
namespace Win32Applied
{
class Program
{
[DllImport("Kernel32.dll")]
public static extern bool SetConsoleTitle(string strMessage);
return 0;
}
}
}
Introduction to Exceptions
Overview
During the execution of a program, the computer will face two types of situations: those
it is prepared to deal with and those it is not. Imagine you write a program that requests
a number from the user:
using System;
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
return 0;
}
}
This is a classic easy program. When it comes up, the user is asked to simply type a
number. The number would then be multiplied by 4 and display the result. Imagine that
a user types something that is not a valid number, such as the name of a country or
somebody’s telephone number. Since this program was expecting a number and it is not
prepared to multiply a string to a number, it would not know what to do. The only
alternative the compiler would have is to send the problem to the operating system,
hoping that the OS would know what to do. What actually happens is that, whenever
the compiler is handed a task, it would try to perform the assignment. If it can’t perform
the assignment, for any reason it is not prepared for, it would produce an error. As a
programmer, if you can anticipate the type of error that could occur in your program,
you can identify the error yourself and deal with it by telling the compiler what to do
when this type of error occurs.
using System;
namespace GeorgetownCleaningServices5
{
public class CleaningOrderInfo
{
// Basic information about an order
public string CustomerName;
public string HomePhone;
public DateTime OrderDate;
public DateTime OrderTime;
// Unsigned numbers to represent cleaning items
public uint NumberOfShirts;
public uint NumberOfPants;
public uint NumberOfDresses;
}
}
5. To create a new class, on the main menu, click Project -> Add Class...
namespace GeorgetownCleaningServices5
{
public class sealed OrderProcessing
{
#region Objects used to process an order
// Price of items
const decimal PriceOneShirt = 0.95M;
const decimal PriceAPairOfPants = 2.95M;
const decimal PriceOneDress = 4.55M;
const decimal TaxRate = 0.0575M; // 5.75%
CleaningOrderInfo cleaningOrder;
#endregion
public OrderProcessing()
{
cleaningOrder = new CleaningOrderInfo();
}
ShowReceipt();
}
namespace GeorgetownCleaningServices5
{
class Program
{
static int Main()
{
OrderProcessing Order = new OrderProcessing();
Order.ProcessOrder();
return 0;
}
}
}
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Peter Moonstruck
Home Phone: (301) 728-8830
Order Date: Saturday, April 22, 2006
Order Time: 8:46 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 5 0.95 4.75
Pants 2 2.95 5.90
Dresses 3 4.55 13.65
------------------------------------
Total Order: $24.30
Tax Rate: 5.75 %
Tax Amount: $1.40
Net Price: $25.70
------------------------------------
Amount Tended: $30.00
Difference: $4.30
====================================
Press any key to continue . . .
Exceptional Behaviors
1. Trying the normal flow: To deal with the expected behavior of a program, use
the try keyword as in the following syntax:
try {Behavior}
The try keyword is required. It lets the compiler know that you are attempting a
normal flow of the program. The actual behavior that needs to be evaluated is
included between an opening curly bracket “{“ and a closing curly bracket “}”.
Inside of the brackets, implement the normal flow that the program must follow, at
least for this section of the code. Here is an example:
using System;
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
}
return 0;
}
}
2. Catching Errors: During the flow of the program as part of the try section, if an
abnormal behavior occurs, instead of letting the program crash or instead of letting
the compiler send the error to the operating system, you can transfer the flow of
the program to another section that can deal with it. The syntax used by this
section is:
catch {WhatToDo}
This section always follows the try section. There must not be any code between
the try’s closing bracket and the catch section. The catch keyword is required
and follows the try section. Combined with the try block, the syntax of an
try
{
Console.Write("Type a number: ");
Number = double.Parse(Console.ReadLine());
return 0;
}
}
namespace GeorgetownCleaningServices5
{
class OrderProcessing
{
. . . No Change
try
{
Console.Write("Number of Pants: ");
Order.NumberOfPants = uint.Parse(Console.ReadLine());
}
catch
{
}
try
{
Console.Write("Number of Dresses: ");
Order.NumberOfDresses = uint.Parse(Console.ReadLine());
}
catch
{
}
. . . No Change
ShowReceipt();
}
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
}
catch
{
Console.WriteLine("There was a problem with the program");
}
return 0;
}
}
Of course, this type of message is not particularly clear but this time, the program will
not crash. In the next sections, we will learn better ways of dealing with the errors and
the messages.
namespace GeorgetownCleaningServices5
{
class OrderProcessing
{
. . . No Change
try
{
Console.Write("Number of Pants: ");
Order.NumberOfPants = uint.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine("The value you typed for the number of "
+
"pair or pants is not a valid number");
}
try
{
Console.Write("Number of Dresses: ");
Order.NumberOfDresses = uint.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine("The value you typed for the number of "
+
"dresses is not a valid number");
}
. . . No Change
try
{
Console.Write("Amount Tended? ");
AmountTended = decimal.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine(
"You were asked to enter an amount of money but...");
}
ShowReceipt();
}
C# 3.0 Practical Learning 452
private void ShowReceipt()
{
. . . No Change
}
}
}
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Alexandria
Home Phone: (102) 797-8382
Order Date: Monday, April 02, 2001
Order Time: 9:22 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 6 0.95 5.70
Pants 0 2.95 0
Dresses 5 4.55 22.75
------------------------------------
Total Order: $28.45
Tax Rate: 5.75 %
Tax Amount: $1.64
Net Price: $30.09
------------------------------------
Amount Tended: $0.00
Difference: ($30.09)
====================================
In exception handling, errors are dealt with in the catch section. To do this, use catch
as if it were a method. This means that, on the right side of catch, open a parenthesis,
declare a variable of the type of exception you want to deal with. By default, an
exception is first of type Exception. Based on this, a typical formula to implement
exception handling is:
try
{
// Process the normal flow of the program here
}
catch(Exception e)
{
// Deal with the exception here
}
When an exception occurs in the try section, code compilation is transferred to the
catch section. If you declare the exception as an Exception type, this class will identify
the error. One of the properties of the Exception class is called Message. This property
contains a string that describes the type of error that occurred. You can then access this
Exception.Message property to display an error message if you want. Here is an
example:
using System;
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
return 0;
}
}
As you can see, one of the strengths of the Exception.Message property is that it gives
you a good indication of the type of problem that occurred. Sometimes, the message
provided by the Exception class may not appear explicit enough. In fact, you may not
want to show it to the user since, as in this case, the user may not understand what the
expression "correct format" in this context means and why it is being used. As an
alternative, you can create your own message and display it to the user. Here is an
example:
using System;
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
}
catch(Exception ex)
{
return 0;
C# 3.0 Practical Learning 455
}
}
You can also combine the Exception.Message message and your own message:
using System;
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
}
catch(Exception ex)
{
Console.Write(ex.Message);
Console.WriteLine(
" Consequently, The operation could not be carried because
" +
"the number you typed is not valid");
}
return 0;
}
}
Introduction
There are two main ways you can use one of the classes of the .NET Framework. If you
know for sure that a particular exception will be produced, pass its name to the catch()
clause. You don't have to name the argument. Then, in the catch() section, display a
custom message. The second option you have consists of using the throw keyword. We
will study it later.
From now on, we will try to always indicate the type of exception that could be thrown if
something goes wrong in a program
When studying data formatting in Lesson 5, we saw that everything the user types
into an application using the keyboard is primarily a string and that you must convert it
to the appropriate type before using it. When you request a specific type of value from
the user, after the user has typed it and you decide to convert it to the appropriate type,
if your conversion fails, the program produces an error. The error is of the
FormatException class.
class Program
{
static int Main()
{
double side;
Console.WriteLine("Square Processing");
try
{
Console.Write("Enter Side: ");
side = double.Parse(Console.ReadLine());
Console.WriteLine("\nSquare Characteristics");
Console.WriteLine("Side: {0}", side);
Console.WriteLine("Perimeter: {0}", side * 4);
}
catch(FormatException)
{
Console.WriteLine("\nYou typed an invalid number");
}
return 0;
}
}
1. Change the OrderProcessing.cs file as follows (this includes the complete current
version of the file):
using System;
namespace GeorgetownCleaningServices5
{
class OrderProcessing
{
#region Objects used to process an order
// Price of items
const decimal PriceOneShirt = 0.95M;
const decimal PriceAPairOfPants = 2.95M;
const decimal PriceOneDress = 4.55M;
const decimal TaxRate = 0.0575M; // 5.75%
CleaningOrderInfo cleaningOrder;
#endregion
public OrderProcessing()
{
cleaningOrder = new CleaningOrderInfo();
}
try
{
Console.Write("Enter the order date(mm/dd/yyyy): ");
cleaningOrder.OrderDate =
DateTime.Parse(Console.ReadLine());
ShowReceipt();
}
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Allen Dons
Home Phone: 202-442-0400
Order Date: Thursday, July 14, 2005
Order Time: 8:46 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 5 0.95 4.75
Pants 2 2.95 5.90
Dresses 0 4.55 0.00
------------------------------------
Total Order: $10.65
Tax Rate: 5.75 %
Tax Amount: $0.61
Net Price: $11.26
------------------------------------
Amount Tended: $15.00
Difference: $3.74
====================================
Press any key to continue . . .
C# 3.0 Practical Learning 461
3. Close the DOS window
// An Exercise class
class Exercise
{
static int Main()
{
byte NumberOfPages;
return 0;
}
When a value beyond the allowable range is asked to be stored in memory, the compiler
produces (the expression is "throws" as we will learn soon) an error of the
OverflowException class. Here is an example of running the program:
As with the other errors, when this exception is thrown, you should take an appropriate
action.
// An Exercise class
class Exercise
{
static int Main()
{
DateTime DateHired;
return 0;
}
}
If the user types a value that cannot be converted into a valid date, the compiler
produces an ArgumentOutOfRangeException exception. Here is an example of running
the above program:
Enter Date Hired: 1244/04/258
One way you can avoid this is to guide the user but still take appropriate actions.
Introduction
As mentioned in the previous lesson, the Exception class is equipped with a Message
property that holds a string about the error that occurred. The message of this property
may not be particularly useful to a user. Fortunately, you can create your own message
and pass it to the Exception class. To be able to receive custom messages, the
Exception class provides the following constructor:
Besides using this class or one of its derived classes in a catch clause, you can call this
constructor to give a new and customized implementation of the exception.
2. To create a new class, in the Class View, right-click the name of the project,
position the mouse on Add and click Class...
using System;
namespace RealEstate3
{
public enum PropertyCondition
{
Unknown,
Excellent,
Good,
NeedsRepair,
BadShape
}
public Property()
{
}
namespace RealEstate3
{
public class HouseType : Property
{
private short nbrOfStories;
private bool basement;
private bool garage;
10.To create another class based on the Property class, change the file as follows:
using System;
namespace RealEstate3
{
{
private bool handicap;
11.
12.To create a new class, in the Solution Explorer, right-click RealEstate3, position the
mouse on Add and click Class...
namespace RealEstate3
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
public PropertyListing()
{
C# 3.0 Practical Learning 468
prop = new Property();
hse = new HouseType();
cond = new Condominium();
}
try
{
Console.WriteLine("\nProperties Conditions");
Console.WriteLine("1. Excellent");
Console.WriteLine("2. Good (may need minor repair)");
Console.WriteLine("3. Needs Repair");
Console.Write("4. In Bad Shape (property needs ");
Console.WriteLine("major repair or rebuild)");
Console.Write("Enter Property Condition: ");
condition = short.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
if (condition == 1)
ListProperty.Condition = PropertyCondition.Excellent;
else if (condition == 2)
ListProperty.Condition = PropertyCondition.Good;
else if (condition == 3)
ListProperty.Condition = PropertyCondition.NeedsRepair;
else if (condition == 4)
ListProperty.Condition = PropertyCondition.BadShape;
else
ListProperty.Condition = PropertyCondition.Unknown;
switch ((PropertyType)propType)
{
C# 3.0 Practical Learning 469
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
try
{
Console.Write(
"Does it have an indoor car garage (y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Indoor Car Garage
Answer");
}
try
{
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Basement Answer");
}
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
Console.Write("Does it have an indoor car garage
(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
C# 3.0 Practical Learning 470
House.IndoorGarage = false;
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
break;
case PropertyType.Condominium:
Type = PropertyType.Condominium;
Console.Write(
"\nIs the building accessible to handicapped (y/n):
");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
Condo.HandicapAccessible = true;
else
Condo.HandicapAccessible = false;
break;
default:
Type = PropertyType.Unknown;
break;
}
try
{
Console.Write("\nHow many bedrooms? ");
ListProperty.Bedrooms = short.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
try
{
Console.Write("How many bathrooms? ");
ListProperty.Bathrooms = float.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
try
{
Console.Write("Year built: ");
ListProperty.YearBuilt = int.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
Console.WriteLine(ex.Message);
}
try
{
Console.Write("Property Value: ");
ListProperty.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException ex)
{
C# 3.0 Practical Learning 471
Console.WriteLine(ex.Message);
}
}
switch (Type)
{
case PropertyType.SingleFamily:
case PropertyType.Townhouse:
Type = PropertyType.SingleFamily;
Console.WriteLine("Stories: {0}",
House.Stories);
Console.WriteLine("Has Indoor Car Garage: {0}",
House.IndoorGarage);
Console.WriteLine("Finished Basement: {0}",
House.FinishedBasement);
break;
case PropertyType.Condominium:
Console.WriteLine("Handicapped Accessible Building:
{0}",
Condo.HandicapAccessible);
break;
}
Console.WriteLine("Condition: {0}",
ListProperty.Condition);
Console.WriteLine("Bedrooms: {0}",
ListProperty.Bedrooms);
Console.WriteLine("Bathrooms: {0}",
ListProperty.Bathrooms);
Console.WriteLine("Year Built: {0}",
ListProperty.YearBuilt);
Console.WriteLine("Market Value: {0:C}",
ListProperty.Value);
}
}
}
namespace RealEstate3
{
public static class Program
{
static int Main()
{
PropertyListing listing = new PropertyListing();
C# 3.0 Practical Learning 472
listing.CreateListing();
Console.WriteLine("\n");
listing.ShowProperty();
Console.WriteLine();
return 0;
}
}
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 276744
Property Type: SingleFamily
Stories: -2
Has Indoor Car Garage: False
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 1
Bathrooms: 3684634
Year Built: 87324
Market Value: $2.00
To customize the throwing of an exception, in the section of code where you are
anticipating the error, type the throw keyword followed by a new instance of the
Exception class (or one of its derived classes) using the constructor that takes a string.
Here is an example:
using System;
class Program
{
static int Main()
{
double Operand1, Operand2;
double Result = 0.00;
char Operator;
Console.WriteLine(
"This program allows you to perform an operation on two
numbers");
try
{
Console.Write("Enter a number: ");
Operand1 = double.Parse(Console.ReadLine());
Console.Write("Enter an operator: ");
Operator = char.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Operand2 = double.Parse(Console.ReadLine());
switch (Operator)
{
case '+':
Result = Operand1 + Operand2;
break;
case '-':
Result = Operand1 - Operand2;
case '*':
Result = Operand1 * Operand2;
break;
case '/':
Result = Operand1 / Operand2;
break;
default:
Console.WriteLine("Bad Operation");
break;
}
Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2,
Result);
}
catch (Exception ex)
{
Console.WriteLine("\nOperation Error: {0} is not a valid operator",
ex.Message);
}
return 0;
}
}
namespace RealEstate3
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
class PropertyListing
C# 3.0 Practical Learning 475
{
. . . No Change
switch ((PropertyType)propType)
{
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
if (House.Stories < 1)
{
House.Stories = 1;
throw new OverflowException(
"The number of stories must be positive");
}
}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}
. . . No Change
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
if (House.Stories < 1)
{
House.Stories = 1;
throw new OverflowException(
"The number of stories must be positive");
}
}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}
. . . No Change
}
. . . No Change
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 2
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 463864
Property Type: Townhouse
Stories: 1
Has Indoor Car Garage: False
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 1
Bathrooms: 0.00
Year Built: 2994
Market Value: $425,885.00
try {
// Code to Try
}
catch(Arg1)
{
// One Exception
}
catch(Arg2)
{
// Another Exception
}
1. Following the normal flow of the program, the compiler enters the try block
2. If no exception occurs in the try block, the rest of the try block is executed
If an exception occurs in the try block, the compiler registers the type of error that
occurred. If there is a throw line, the compiler registers it also:
b. The compiler examines the first catch. If the first catch matches the
thrown error, that catch executes and the exception handling routine may
seize. If the first catch doesn’t match the thrown error, the compiler
proceeds with the next catch
c. The compiler checks the next match, if any, and proceeds as in the first
catch. This continues until the compiler finds a catch that matches the
thrown error
d. If one of the catches matches the thrown error, its body executes. If no
catch matches the thrown error, the compiler calls the Exception class and
uses the default message
Multiple catches are written if or when a try block is expected to throw different types of
errors. Once again, consider the previous program. That program works fine as long as
the user types a valid sequence of values made of a number, a valid arithmetic operator,
and a number. Anything else, such as an invalid number, an unexpected operator, or a
wrong sequence (such as a number then another number instead of an operator), would
cause an error. Obviously various bad things could happen when this program is
running. To handle the exceptions that this program could produce, you can start with
the most likely problem that would occur. Trusting that a user is able to provide the two
numbers that are requested, it is possible that a user would type an invalid operator. For
example, for this program we will perform only the addition (+), the subtraction(-), the
multiplication(*), and the division(/). Therefore, we will first validate the operator. This
can be done as follows:
C# 3.0 Practical Learning 478
using System;
class Program
{
static int Main()
{
double Operand1, Operand2;
double Result = 0.00;
char Operator;
try
{
Console.Write("Enter a number: ");
Operand1 = double.Parse(Console.ReadLine());
Console.Write("Enter an operator: ");
Operator = char.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Operand2 = double.Parse(Console.ReadLine());
switch (Operator)
{
case '+':
Result = Operand1 + Operand2;
break;
case '-':
Result = Operand1 - Operand2;
break;
case '*':
Result = Operand1 * Operand2;
break;
case '/':
Result = Operand1 / Operand2;
break;
default:
Console.WriteLine("Bad Operation");
break;
}
Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator, Operand2,
Result);
}
catch (Exception ex)
{
Console.WriteLine("\nOperation Error: {0} is not a valid operator",
ex.Message);
}
C# 3.0 Practical Learning 479
return 0;
}
}
When this program runs, if the user provides a valid number followed by a wrong
operator, we call the Exception(string message) constructor and pass it a string
converted from the character that was typed.
Imagine that the user wants to perform a division. You need to tell the compiler what to
do if the user enters the denominator as 0 (or 0.00). If this happens, probably the best
option is to display a message and get out. Fortunately, the .NET Framework provides
the DivideByZeroException class to deal with an exception caused by division by
zero. As done with the message passed to the Exception class, you can compose your
own message and pass it to the DivideByZeroException(string message)
constructor.
class Program
{
static int Main()
{
double Operand1, Operand2;
double Result = 0.00;
char Operator;
try
{
Console.Write("Enter a number: ");
Operand1 = double.Parse(Console.ReadLine());
Console.Write("Enter an operator: ");
Operator = char.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Operand2 = double.Parse(Console.ReadLine());
switch (Operator)
{
case '+':
Result = Operand1 + Operand2;
break;
case '-':
case '*':
Result = Operand1 * Operand2;
break;
case '/':
Result = Operand1 / Operand2;
break;
default:
Console.WriteLine("Bad Operation");
break;
}
Console.WriteLine("\n{0} {1} {2} = {3}", Operand1, Operator,
Operand2, Result);
}
catch (DivideByZeroException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("\nOperation Error: {0} is not a valid operator",
ex.Message);
}
return 0;
}
}
When running this program, if the user types a wrong operator, the compiler gets out of
the try block and looks for a catch that takes an Exception as argument. It finds the
second and executes it. If the user enters the right values (a number, an operator, and
another number), then the compiler finds out if the operator entered was a forward
slash “/” used to perform a division. If the user wants to perform a division, the compiler
finds out if the second operand, the denominator, is 0. If it is, we create a
DivideByZeroException instance and pass our own message to it. Based on this
exception, the compiler gets out of the try block and starts looking for a catch block
that takes a DivideByZeroException argument. It finds it in the first catch. Therefore,
the compiler executes it.
namespace RealEstate3
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
C# 3.0 Practical Learning 481
Condominium
}
class PropertyListing
{
private Property prop;
private HouseType hse;
private Condominium cond;
private PropertyType tp;
public PropertyListing()
{
prop = new Property();
hse = new HouseType();
cond = new Condominium();
}
try
{
Console.WriteLine("\nProperties Conditions");
Console.WriteLine("1. Excellent");
Console.WriteLine("2. Good (may need minor repair)");
Console.WriteLine("3. Needs Repair");
Console.Write("4. In Bad Shape (property needs ");
Console.WriteLine("major repair or rebuild)");
Console.Write("Enter Property Condition: ");
condition = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you typed for the property condition is not
good");
}
catch (Exception)
{
Console.WriteLine("Something unacceptable has just
happened");
}
if (condition == 1)
ListProperty.Condition = PropertyCondition.Excellent;
else if (condition == 2)
ListProperty.Condition = PropertyCondition.Good;
else if (condition == 3)
ListProperty.Condition = PropertyCondition.NeedsRepair;
else if (condition == 4)
ListProperty.Condition = PropertyCondition.BadShape;
else
ListProperty.Condition = PropertyCondition.Unknown;
switch ((PropertyType)propType)
{
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
if (House.Stories < 1)
{
House.Stories = 1;
throw new OverflowException("The number of levels must be
positive");
C# 3.0 Practical Learning 483
}
}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}
catch (FormatException)
{
Console.WriteLine("The number you entered for the stories is not
allowed");
}
catch (Exception)
{
Console.WriteLine("This is one of those abnormal behaviors");
}
try
{
Console.Write("Does it have an indoor car garage
(y/n): ");
answer = char.Parse(Console.ReadLine());
try
{
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Basement Answer");
}
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
if (House.Stories < 1)
{
House.Stories = 1;
throw new OverflowException("The number of levels must be
positive");
C# 3.0 Practical Learning 484
}
}
catch (OverflowException ex)
{
Console.WriteLine(ex.Message);
}
catch (FormatException)
{
Console.WriteLine("The number you entered for the stories is not
allowed");
}
catch (Exception)
{
Console.WriteLine("This is one of those abnormal
behaviors");
}
case PropertyType.Condominium:
Type = PropertyType.Condominium;
Console.Write("\nIs the building accessible to handicapped
(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
Condo.HandicapAccessible = true;
else
Condo.HandicapAccessible = false;
break;
default:
Type = PropertyType.Unknown;
break;
}
try
{
Console.Write("\nHow many bedrooms? ");
ListProperty.Bedrooms = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine(
"The value you entered for the number of bedrooms is not
acceptable");
}
catch (Exception)
C# 3.0 Practical Learning 485
{
Console.WriteLine("The program has decided to stop");
}
try
{
Console.Write("How many bathrooms? ");
ListProperty.Bathrooms = float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you decided to enter for the bedrooms is
rejected");
}
catch (Exception)
{
Console.WriteLine("The computer doesn't like what is
going on");
}
try
{
Console.Write("Year built: ");
ListProperty.YearBuilt = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You didn't enter a valid number for the year built");
}
catch (Exception)
{
Console.WriteLine("Whatever, whatever, whatever");
}
try
{
Console.Write("Property Value: ");
ListProperty.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine(
"The value of a property must be a good decimal number");
}
catch (Exception)
{
Console.WriteLine(
"This is where the application draws the line: it stops!");
}
}
case PropertyType.Condominium:
Console.WriteLine("Handicapped Accessible Building:
{0}",
Condo.HandicapAccessible);
break;
}
Console.WriteLine("Condition: {0}",
ListProperty.Condition);
Console.WriteLine("Bedrooms: {0}",
ListProperty.Bedrooms);
Console.WriteLine("Bathrooms: {0:F}",
ListProperty.Bathrooms);
Console.WriteLine("Year Built: {0}",
ListProperty.YearBuilt);
Console.WriteLine("Market Value: {0:C}",
ListProperty.Value);
}
}
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 4
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 228046
Property Type: SingleFamily
Stories: 1
Has Indoor Car Garage: True
Finished Basement: False
Condition: BadShape
Bedrooms: 1
Bathrooms: 0.00
Year Built: 0
Market Value: $0.00
Exception Nesting
The calculator simulator we have studied so far performs a division as one of its
assignments. We learned that, in order to perform any operation, the compiler must first
make sure that the user has entered a valid operator. Provided the operator is one of
those we are expecting, we also must make sure that the user typed valid numbers.
Even if these two criteria are met, it was possible that the user enter 0 for the
denominator. The block that is used to check for a non-zero denominator depends on
the exception that validates the operators. The exception that could result from a zero
denominator depends on the user first entering a valid number for the denominator.
class Program
{
static int Main()
{
Console.WriteLine(
"This program allows you to perform an operation on two
numbers");
try
{
Console.Write("Enter a number: ");
Operand1 = double.Parse(Console.ReadLine());
Console.Write("Enter an operator: ");
Operator = char.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Operand2 = double.Parse(Console.ReadLine());
switch (Operator)
{
case '+':
Result = Operand1 + Operand2;
Console.WriteLine("\n{0} + {1} = {2}", Operand1,
Operand2, Result);
break;
case '-':
Result = Operand1 - Operand2;
Console.WriteLine("\n{0} - {1} = {2}", Operand1,
Operand2, Result);
break;
case '*':
Result = Operand1 * Operand2;
Console.WriteLine("\n{0} * {1} = {2}", Operand1,
Operand2, Result);
break;
case '/':
// The following exception is nested in the previous
try
try
{
if (Operand2 == 0)
throw new DivideByZeroException("Division by zero is
not allowed");
return 0;
}
}
One of the most effective techniques used to deal with code is to isolate assignments.
We learned this when studying methods of classes. For example, the switch statement
that was performing the operations in the “normal” version of our program can be
written as follows:
using System;
class Program
{
static int Main()
{
double Number1, Number2;
double Result = 0.00;
char Operator;
Console.WriteLine(
"This program allows you to perform an operation on two
numbers");
try
{
Console.WriteLine("To proceed, enter");
return 0;
}
switch (Symbol)
{
case '+':
Result = Value1 + Value2;
break;
case '-':
Result = Value1 - Value2;
break;
case '*':
Result = Value1 * Value2;
break;
case '/':
Result = Value1 / Value2;
break;
}
return Result;
}
}
You can still use regular methods along with methods that handle exceptions. As done in
Main(), any method of a program can take care of its own exceptions that would occur
in its body. Here is an example of an exception handled in a method:
using System;
class Program
{
static int Main()
{
double Number1, Number2;
double Result = 0.00;
char Operator;
Console.WriteLine(
"This program allows you to perform an operation on two
numbers");
try
{
Console.WriteLine("To proceed, enter");
return 0;
}
switch (Symbol)
{
case '+':
Result = Value1 + Value2;
Console.WriteLine("\n{0} + {1} = {2}", Value1, Value2,
Result);
break;
case '-':
Result = Value1 - Value2;
Console.WriteLine("\n{0} - {1} = {2}", Value1, Value2,
Result);
break;
case '*':
Result = Value1 * Value2;
Console.WriteLine("\n{0} * {1} = {2}", Value1, Value2,
Result);
break;
case '/':
// The following exception is nested in the previous try
try
{
if (Value2 == 0)
throw new DivideByZeroException("Division by zero is not
allowed");
return Result;
}
}
Isolating assignments and handing them to method is an important matter in the area of
application programming. Consider a program that handles a simple exception such as
this one:
using System;
try
{
Console.Write("Enter a number: ");
Number1 = double.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Number2 = double.Parse(Console.ReadLine());
if (Number2 == 0)
throw new DivideByZeroException("Division by zero is not
allowed");
return 0;
}
}
One of the ways you can use methods in exception routines is to have a central method
that receives variables, and sends them to other external methods. The external method
tests the value of a variable. If an exception occurs, the external method displays or
sends a throw. This throw can be picked up by the method that sent the error. Observe
the following example that implements this scenario:
using System;
class Program
{
static int Main()
{
double Number1, Number2;
try
{
Console.Write("Enter a number: ");
Number1 = double.Parse(Console.ReadLine());
Console.Write("Enter a number: ");
Number2 = double.Parse(Console.ReadLine());
return 0;
}
// If an exception occurred,
if( b == 0 ) // then throw a string to the function caller
throw new DivideByZeroException("Division by zero is not
allowed");
Result = a / b;
Console.WriteLine("\n{0} / {1} = {2}", a, b, Result);
}
}
In this program, the Division method receives two values that it is asked to perform a
division with. The Division method analyzes the second argument that represents the
denominator. If this argument is zero, an exception is found and the Division method
throws a DivideByZeroException exception.
A method can also be called to perform more than one test to eventually throw more
than one exception. Such a method can (and should) be programmed to throw different
types of exceptions.
Custom Exceptions
Introduction
As seen in the previous lesson and in the above sections, exception handling is a great
part of the .NET Framework. As high as it is supported by various classes of the .NET, it
is possible that you want to further customize the handling of exceptions in your
application. One way you can do this is to create your own exception class.
The Exception class of the .NET Framework is a great tool for handling exceptions in a
C# application. To deal with particular errors, various classes are derived from
Exception. If for some reason the Exception class and none of the Exception-based
classes fulfills your requirement, you can derive a new class from Exception or from
one of the available Exception-based classes.
To derive a class from Exception or from one of its classes, simply follow the rules we
reviewed from class inheritance. Here is an example of a class based on Exception:
There is no real rule to follow as to what class to derive from but it may be a good idea
to derive your class from one that already addresses your issue but not the way you
want. For example, if you want to create a class that would process numeric values but
you think the FormatException class is not doing what you want, you can derive your
class from FormatException.
After deriving the class, you can add the necessary members as you see fit. Remember
that the primary characteristic of an exception is to present a message to the user. In
Exception-based classes, this message is represented by the Message property.
Therefore, if you want to prepare a custom message for your class, you can override
or new this property. Here is an example:
public class IntegerException : Exception
{
public override string Message
{
get
{
return "The value you entered is not a valid integer";
}
}
}
Once you have created and customized your exceptional class, you can use it the same
way you would another exception class, such as throwing it. Here is an example
using System;
public DigitException(char x)
{
c = x;
}
class Program
{
static int Main()
{
try
{
char chNumber = '0';
return 0;
}
}
Introduction
Imagine you want to create a program that would use a series of numbers. In algebra,
we represent such a series as follows: X 1, X2, X3, X4, X5. You can also represent a list of
names as follows:
Alex
Gaston
Hermine
Jerry
So far, to use a series of items, we were declaring a variable for each of them. If the list
was made of numbers, we would declare variables for such numbers as follows:
using System;
return 0;
}
}
Instead of using individual variables that share the same characteristics, you can group
them in an entity like a regular variable. This group is called an array. Therefore, an
array is a series of items of the same kind. It could be a group of numbers, a group of
cars, a group of words, etc but all items of the array must be of the same type.
Array Creation
Before creating an array, you must first decide the type its items will be made of. Is it a
group of numbers, a group of chairs, a group of buttons on a remote control? This
information allows the compiler to know how much space each item of the group will
require. This is because each item of the group will occupy its own memory space, just
like any of the variables we have used so far.
After deciding about the type of data of each item that makes up the series, you must
use a common name to identify them. The name is simply the same type of name you
would use for a variable as we have used so far. The name allows you and the compiler
to identify the area in memory where the items are located.
Thirdly, you must specify the number of items that will constitute the group. For the
compiler to be able to allocate an adequate amount of space for the items of the list,
once it knows how much space each item will require, it needs to know the number of
items so an appropriate and large enough amount of space can be reserved. The
number of items of an array is included in square brackets, as in [5].
An array is considered a reference type. Therefore, an array requests its memory using
the new operator. Based on this, one of the formulas to declare an array is:
DataType[] VariableName = new DataType[Number];
Alternatively, you can use the var keyword to create an array. The formula to use would
be:
var VariableName = new DataType[Number];
In these formulas, the DataType factor can be one of the types we have used so far
(char, int, float, double, decimal, string, etc). It can also be the name of a class
as we will learn in Lesson 23. Like a normal variable, an array must have a name,
represented in our formula as VariableName. The square brackets on the left of the
assignment operator are used to let the compiler know that you are declaring an array
instead of a regular variable. The new operator allows the compiler to reserve memory.
The Number factor is used to specify the number of items of the list.
Using the var keyword, this array can also be declared as follows:
C# 3.0 Practical Learning 499
using System;
namespace VideoCollection1
{
public class Program
{
static void Main(string[] args)
{
long[] ShelfNumbers = new long[10];
string[] Titles = new string[10];
string[] Directors = new string[10];
int[] Lengths = new int[10];
string[] Ratings = new string[10];
double[] Prices = new double[10];
}
}
}
When creating an array, you can specify the number of items that make up its list. Each
item of the series is referred to as a member or an element of the array. Once the array
has been created, each one of its members is initialized with a 0 value. Most, if not all,
of the time, you will need to change the value of each member to a value of your
choice. This is referred to as initializing the array.
An array is primarily a variable; it is simply meant to carry more than one value. Like
every other variable, an array can be initialized. There are two main techniques you can
use to initialize an array. If you have declared an array as done above, to initialize it,
you can access each one of its members and assign it a desired but appropriate value.
In algebra, if you create a series of values as X 1, X2, X3, X4, and X5, each member of this
series can be identified by its subscript number. In this case the subscripts are 1, 2, 3, 4,
and 5. This subscript number is also called an index. In the case of an array also, each
member can be referred to by an incremental number called an index. A C# (like a C/C+
In C#, the index of a member of an array is written in its own square brackets. This is
the notation you would use to locate each member. One of the actions you can take
would consist of assigning it a value. Here is an example:
using System;
Numbers[0] = 12.44;
Numbers[1] = 525.38;
Numbers[2] = 6.28;
Numbers[3] = 2448.32;
Numbers[4] = 632.04;
}
}
Besides this technique, you can also initialize the array as a whole when declaring it. To
do this, on the right side of the declaration, before the closing semi-colon, type the
values of the array members between curly brackets and separated by a comma. Here is
an example:
using System;
If you use this second technique, you don't have to specify the number of items in the
series. In this case, you can leave all square brackets empty:
using System;
If you leave the square brackets empty, the compiler will figure out the number of
items.
namespace VideoCollection1
{
class Program
{
static void Main(string[] args)
{
long[] ShelfNumbers = new long[]
{
2985, 8024, 5170, 1304, 9187,
1193, 3082, 8632, 4633, 9623
};
string[] Titles = new string[]
{
"The Distinguished Gentleman",
"A Perfect Murder", "Chalte Chalte",
"Ransom", "Not Another Teen Movie",
"Madhubaala", "Get Shorty",
"Sneakers", "Born Invincible", "Hush"
};
string[] Directors = new string[]
{
"Jonathan Lynn", "Andrew Davis", "Aziz Mirza",
"Ron Howard", "Joel Gallen", "Shivram Yadav",
"Barry Sonnenfeld", "Paul Alden Robinson",
"Unknown", "Jonathan Darby"
};
int[] Lengths = new int[]
{
112, 108, 145, 121, 100, 0, 105, 126, 90, 96
};
string[] Ratings = new string[]
{
"R", "R", "N/R", "R", "Unrated",
"N/R", "R", "PG-13", "N/R", "PG-13"
};
double[] Prices = new double[]
{
14.95D, 19.95D, 22.45D, 14.95D, 9.95D,
17.50D, 9.95D, 9.95D, 5.95D, 8.75D
};
}
}
}
The values can also come from constant variables. Here is an example:
using System;
The values can also come from calculations, whether the calculation is from an initialized
variable or made locally in the curly brackets. Here is an example:
using System;
The rule to follow is that, at the time the array is created, the compiler must be able to
know exactly the value of each member of the array, no guessing.
C# 3.0 Practical Learning 503
All of the arrays we have declared so far were using only numbers. The numbers we
used were decimal constants. If the array is made of integers, you can use decimal,
hexadecimal values, or a combination of both. Here is an example:
using System;
An array can have types of values of any of the data types we have used so far. The
rule to follow is that all members of the array must be of the same type. For example,
you can declare an array of Boolean values, as long as all values can be evaluated to
true or false. Here is an example:
using System;
As stated already, each values of a Boolean array must be evaluated to true or false.
This means that you can use variables or expressions as members of the array. Here is
an example:
using System;
As we will see when studying arrays and classes, you can use this technique to create
an array of dates, times, or date and time values. Here is an example:
using System;
Introduction
After initializing an array, which means after each of its members has been given a
value, you can access a member of the array to get, manipulate or even change its
value. To access a member of the array, you use the square brackets as we saw above.
As done for normal variables, one of the reasons of accessing a member of an array
would be to display its value on the console screen, which can be done by passing it to a
Console.Write() or a Console.WriteLine() method. Here is an example:
using System;
Console.Write(Numbers[3]);
return 0;
}
}
In the same way, you can use the curly brackets notation to display the value of a
member:
using System;
return 0;
}
}
In the same way, you can access 1, a few or all members of the array.
namespace VideoCollection1
{
class Program
{
static void Main(string[] args)
{
long[] ShelfNumbers = new long[]
{
2985, 8024, 5170, 1304, 9187, 1193, 3082, 8632
};
. . . No Change
Console.WriteLine("===============================");
Console.WriteLine("Video Information");
Console.WriteLine("-------------------------------");
Console.WriteLine("Shelf #: {0}", ShelfNumbers[1]);
Console.WriteLine("Title: {0}", Titles[1]);
Console.WriteLine("Director: {0}", Directors[1]);
Console.WriteLine("Length: {0} minutes", Lengths[1]);
Console.WriteLine("Rating: {0}", Ratings[1]);
Console.WriteLine("Price: {0}", Prices[1]);
Console.WriteLine("===============================");
}
}
}
In this formula, the for keyword, the parentheses, and the semi-colons are required.
The DataType factor is used to specify how you will count the members of the array.
The Initializer specifies how you would indicate the starting of the count. As seen in
Lesson 12, this initialization could use an initialized int-based variable.
The EndOfRange specifies how you would stop counting. If you are using an array, it
should combine a conditional operation (<, <=, >, >=, or !=) with the number of
members of the array minus 1.
The Increment factor specifies how you would move from one index to the next.
Here is an example:
using System;
return 0;
}
}
When using a for loop, you should pay attention to the number of items you use. If you
use a number n less than the total number of members - 1, only the first n members of
the array would be accessed. Here is an example:
using System;
return 0;
}
}
On the other hand, if you use a number of items higher than the number of members
minus one, the compiler would throw an IndexOutOfRangeException exception. Here
is an example:
using System;
return 0;
}
}
Therefore, when the number of items is higher than the number of members - 1, the
compiler may process all members. Then, when it is asked to process members beyond
the allowed range, it finds out that there is no other array member. So it gets upset.
You could solve the above problem by using exception handling to handle an
IndexOutOfRangeException exception. Here is an example:
using System;
try
{
for (var i = 0; i < 12; i++)
Console.WriteLine("Number: {0}", Numbers[i]);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("You tried to access values beyond " +
"the allowed range of the members of the
array.");
}
return 0;
}
}
This solution should not be encouraged. Fortunately, C# and the .NET Framework
provide better solutions.
namespace VideoCollection1
{
class Program
{
static void Main(string[] args)
{
. . . No Change
Console.WriteLine("===============================");
Console.WriteLine("Videos Information");
for (int i = 0; i < 10; i++)
{
Console.WriteLine("===============================");
Console.WriteLine("Video {0}", i + 1);
Console.WriteLine("-------------------------------");
Console.WriteLine("Shelf #: {0}", ShelfNumbers[i]);
Console.WriteLine("Title: {0}", Titles[i]);
Console.WriteLine("Director: {0}", Directors[i]);
Console.WriteLine("Length: {0} minutes", Lengths[i]);
Console.WriteLine("Rating: {0}", Ratings[i]);
Console.WriteLine("Price: {0}", Prices[i]);
}
Console.WriteLine("===============================");
}
}
}
In a for loop, you should know the number of members of the array. If you don't, the
C# language allows you to let the compiler use its internal mechanism to get this count
and use it to know where to stop counting. To assist you with this, C# provides the
foreach operator. To use it, the formula to follow is:
The first factor of this syntax, type, can be var or the type of the members of the array.
It can also be the name of a class as we will learn in Lesson 23.
The statement is what you intend to do with the identifier or as a result of accessing the
member of the array.
Like a for loop that accesses all members of the array, the foreach operator is used to
access each array member, one at a time. Here is an example:
using System;
return 0;
}
}
Anonymous Arrays
Introduction
In previous sections, when creating an array, we were specifying its type. As seen in our
introduction to variables, a good feature of the var keyword is that, when using it to
declare and initialize a variable, you ask the compiler to figure out what type of data the
variable is holding. This concept is also valid for an array.
An anonymous array is an array variable whose type is left to the compiler to determine,
based on the types of values of the array.
As done for variables so far, when creating an array, you can use the var keyword,
initialize the array, but not specify its data type. The formula to use is:
var ArrayName = new[] { Initialization };
The formula is almost similar to that of a normal array, with keywords and operators you
are already familiar with. The ArrayName factor is the name of the variable. Notice that
the new keyword is directly followed by the square brackets. In the curly brackets, you
must initialize the array by providing the necessary values. For the compiler to be able to
figure out the type and amount of memory to allocate for the array variable, all values
must be of the same type or the same category:
If each value is a number without a decimal part, the compiler checks their range
and concludes whether the array needs 32 bits or 64 bits. Here is an example:
using System;
using System.Linq;
return 0;
}
}
If the values are numeric but at least one of them includes a decimal part, the
compiler concludes that the array is made of floating-point numbers. If you want to
control their precision (float, double, or decimal), add the appropriate suffix to
each value. This also means that you can use a combination of natural and decimal
numbers, but the presence of at least one number with a decimal part would
convert the array into floating point instead of int-based. Here is an example:
using System;
using System.Linq;
return 0;
}
}
If the members are made of true and false values, then compiler will allocate
memory for Boolean values for the array. Here is an example:
using System;
using System.Linq;
return 0;
}
}
If the members contain values included in single-quotes, the array will be treated
as a series of characters. Here is an example:
using System;
using System.Linq;
If the values of the members are included in double-quotes, then the array will be
considered a group of strings. Here is an example:
using System;
using System.Linq;
return 0;
}
}
After creating an anonymous array, you can access each member using its index. Here is
an example that uses a for loop:
using System;
using System.Linq;
return 0;
}
}
In the same way, you can use a foreach statement to access each member of the
array. Here is an example:
using System;
using System.Linq;
return 0;
}
}
Introduction
Because an array is a list of items, it could include values that are not useful in all
scenarios. For example, having an array made of too many values, at one time you may
want to isolate only the first n members of the array, or the last m members of the
array, or a range of members from an index i to an index j. Another operation you may
be interested to perform is to find out if this or that value exists in the array. One more
interesting operation would be to find out what members or how many members of the
array respond to this or that criterion. All these operations are useful and possible with
different techniques.
return 0;
}
}
Imagine you want to access only the first n members of the array. To do this, you can
use an if conditional statement nested in a for or a foreach loop. Here is an example
that produces the first 4 values of the array:
using System;
using System.Linq;
return 0;
}
}
You can use the same technique to get the last m members of the array. You can also
use a similar technique to get one or a few values inside of the array, based on a
return 0;
}
}
namespace VideoCollection1
{
class Program
{
static void Main(string[] args)
{
long[] ShelfNumbers = new long[]
{
2985, 8024, 5170, 1304, 9187,
1193, 3082, 8632, 4633, 9623
};
string[] Titles = new string[]
{
"The Distinguished Gentleman",
"A Perfect Murder", "Chalte Chalte",
"Ransom", "Not Another Teen Movie",
"Madhubaala", "Get Shorty",
"Sneakers", "Born Invincible", "Hush"
};
string[] Directors = new string[]
{
"Jonathan Lynn", "Andrew Davis", "Aziz Mirza",
"Ron Howard", "Joel Gallen", "Shivram Yadav",
C# 3.0 Practical Learning 518
"Barry Sonnenfeld", "Paul Alden Robinson",
"Unknown", "Jonathan Darby"
};
int[] Lengths = new int[]
{
112, 108, 145, 121, 100, 0, 105, 126, 90, 96
};
string[] Ratings = new string[]
{
"R", "R", "N/R", "R", "Unrated",
"N/R", "R", "PG-13", "N/R", "PG-13"
};
double[] Prices = new double[]
{
14.95D, 19.95D, 22.45D, 14.95D, 9.95D,
17.50D, 9.95D, 9.95D, 5.95D, 8.75D
};
long ShelfNumber = 0;
3. When prompted, enter a shelf number and press Enter. Here is an example:
2985 8024 5170 1304 9187 1193 3082 8632 4633
9623
Enter the shelf number of the video you want to check: 8632
===============================
Video Information
C# 3.0 Practical Learning 519
-------------------------------
Shelf #: 8632
Title: Sneakers
Director: Paul Alden Robinson
Length: 126 minutes
Rating: PG-13
Price: 9.95
===============================
Press any key to continue . . .
Introduction
As we have used them so far, an array is primarily a variable. As such, it can be declared
as a member variable of a class. To create a field as an array, you can declare it like a
normal array in the body of the class. Here is an example:
public class CoordinateSystem
{
private int[] Points;
}
Like any field, when an array has been declared as a member variable, it is made
available to all the other members of the same class. You can use this feature to
initialize the array in one method and let other methods use the initialized variable. This
also means that you don't have to pass the array as argument nor do you have to
explicitly return it from a method.
After or when declaring an array, you must make sure you allocate memory for it prior
to using. Unlike C++, you can allocate memory for an array when declaring it. Here is
an example:
public class CoordinateSystem
{
private int[] Points = new int[4];
}
You can also allocate memory for an array field in a constructor of the class. Here is an
example:
public class CoordinateSystem
{
private int[] Points;
public CoordinateSystem()
{
Points = new int[4];
}
}
If you plan to use the array as soon as the program is running, you can initialize it using
a constructor or a method that you know would be called before the array can be used.
Here is an example:
public class CoordinateSystem
C# 3.0 Practical Learning 521
{
private int[] Points;
public CoordinateSystem()
{
Points = new int[4];
Points[0] = 2;
Points[1] = 5;
Points[2] = 2;
Points[3] = 8;
}
}
2. To create a new class, in the Solution Explorer, right-click RenatlProperties1 -> Add
-> Class...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RentalProperties1
{
public enum PropertyType { SingleFamily, Townhouse,
Apartment, Unknown };
public RentalProperty()
{
PropertyNumbers = new long[] {
192873, 498730, 218502, 612739,
457834, 927439, 570520, 734059 };
After an array has been created as a field, it can be used by any other member of the
same class. Based on this, you can use a member of the same class to request values
that would initialize it. You can also use another method to explore the array. Here is an
example:
using System;
public CoordinateSystem()
{
Points = new int[4];
Points[0] = 2;
Points[1] = -5;
Points[2] = 2;
Points[3] = 8;
}
Coordinates.ShowPoints();
return 0;
}
}
namespace RentalProperties1
{
public enum PropertyType { SingleFamily, Townhouse,
Apartment, Unknown };
public RentalProperty()
{
PropertyNumbers = new long[] {
192873, 498730, 218502, 612739,
457834, 927439, 570520, 734059 };
Console.WriteLine("=============================================");
Console.WriteLine("Prop # Property Type Beds Baths Monthly
Rent");
Console.WriteLine("---------------------------------------------");
for (int i = 0; i < 8; i++)
C# 3.0 Practical Learning 524
{
Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}",
PropertyNumbers[i], Types[i], Bedrooms[i],
Bathrooms[i], MonthlyRent[i]);
}
Console.WriteLine("=============================================");
}
}
}
namespace RentalProperties1
{
class Program
{
static void Main(string[] args)
{
RentalProperty Property = new RentalProperty();
Property.ShowListing();
}
}
}
Introduction
The main purpose of using an array is to use various values grouped under one name.
Still, an array is primarily a variable. As such, it can be passed to a method and it can be
returned from a method.
When an array has been passed to a method, it can be used in the body of the method
as any array can be, following the rules of array variables. For example, you can display
its values. The simplest way you can use an array is to display the values of its
members. This could be done as follows:
public class CoordinateSystem
{
public void ShowPoints(int[] Points)
{
Console.WriteLine("Points Coordinates");
Console.WriteLine("P({0}, {1})", Points[0], Points[1]);
Console.WriteLine("Q({0}, {1})", Points[2], Points[3]);
}
}
To call a method that takes an array as argument, simply type the name of the array in
the parentheses of the called method. Here is an example:
using System;
Coordinates.Initialize(System);
Coordinates.ShowPoints(System);
return 0;
}
}
Coordinates.Initialize(ref System);
Coordinates.ShowPoints(System);
return 0;
}
}
Instead of just one, you can create a method that receive more than one array and you
can create a method that receives a combination of one or more arrays and one or more
regular arguments. There is no rule that sets some restrictions.
You can also create a method that takes one or more arrays as argument(s) and returns
a regular value of a primitive type.
Like a normal variable, an array can be returned from a method. This means that the
method would return a variable that carries various values. When declaring or defining
the method, you must specify its data type. When the method ends, it would return an
array represented by the name of its variable.
You can create a method that takes an array as argument and returns another array as
argument.
Remember that a method must always return an appropriate value depending on how it
was declared. In this case, if it was specified as returning an array, then make sure it
returns an array and not a regular variable. One way you can do this is to declare and
possibly initialize a local array variable. After using the local array, you return only its
name (without the square brackets). Here is an example:
using System;
return Coords;
}
}
When a method returns an array, that method can be assigned to an array declared
locally when you want to use it. Remember to initialize a variable with such a method
only if the variable is an array.
Here is an example:
using System;
return Coords;
}
System = Coordinates.Initialize();
Coordinates.ShowPoints(System);
return 0;
}
}
return 0;
}
}
If you initialize an array variable with a method that doesn't return an array, you would
receive an error.
Main()'s Argument
Introduction
When a program starts, it looks for an entry point. This is the role of the Main()
method. In fact, a program, that is an executable program, starts by, and stops with,
the Main() method. The way this works is that, at the beginning, the compiler looks
for a method called Main. If it doesn't find it, it produces an error. If it finds it, it enters
the Main() method in a top-down approach, starting just after the opening curly
bracket. If it finds a problem and judges that it is not worth continuing, it stops and lets
you know. If, or as long as, it doesn't find a problem, it continues line after line, with the
option to even call or execute a method in the same file or in another file. This process
continues to the closing curly bracket "}". Once the compiler finds the closing bracket,
the whole program has ended and stops.
If you want the user to provide additional information when executing your program,
you can take care of this in the Main() method. Consider the following code written in a
file saved as Exercise.cs:
using System;
Console.WriteLine("Employee Payroll");
Console.WriteLine("Full Name: {0}", FullName);
Console.WriteLine("WeeklySalary: {0}",
WeeklySalary.ToString("C"));
return 0;
}
}
To execute the application, at the Command Prompt and after Changing to the Directory
that contains the file, you would type
csc Exercise.cs
and press Enter. To execute the program, you would type the name Exercise and
press Enter. The program would then prompt you for the information it needs.
To compile a program, you would simply type the csc command at the command
prompt. Then, to execute a program, you would type its name at the prompt. If you
distribute a program, you would tell the user to type the name of the program at the
command prompt. In some cases, you may want the user to type additional information
besides the name of the program. To request additional information from the user, you
can pass a string argument to the Main() method. The argument should be passed as
an array and make sure you provide a name for the argument. Here is an example:
using System;
class ObjectName
{
static int Main(string[] args)
{
return 0;
}
}
The reason you pass the argument as an array is so you can use as many values as you
judge necessary. To provide values at the command prompt, the user types the name of
the program followed by each necessary value. Here is an example:
Each of the values the user types is a string. If any one of them is not a string, you
should/must convert/cast its string first to the appropriate value. Consider the following
source code:
using System;
namespace CSharpLessons
{
public class Exercise
{
static int Main(string[] Argument)
{
string FirstName;
string LastName;
Double WeeklyHours;
Double HourlySalary;
FirstName = Argument[0];
LastName = Argument[1];
WeeklyHours = Double.Parse(Argument[2]);
HourlySalary = Double.Parse(Argument[3]);
Console.WriteLine("Employee Payroll");
Console.WriteLine("Full Name: {0}", FullName);
Console.WriteLine("WeeklySalary: {0}",
WeeklySalary.ToString("C"));
return 0;
}
}
}
and press Enter. To execute the program, you would type Exercise followed by a first
name, a last name, and two decimal values. An example would be Exercise
Catherine Engolo 42.50 20.48
An Array of Objects
Introduction
As done for primitive types, you can create an array of values where each member of
the array is based on a formal class. Of course, you must have a class first. You can
use one of the already available classes or you can create your own class. Here is an
example:
using System;
2. To create a new class, in the Solution Explorer, right-click RenatlProperties1 -> Add
-> Class...
namespace RentalProperties2
{
public enum PropertyType
{
SingleFamily, Townhouse,
Apartment, Unknown
};
public RentalProperty()
{
nbr = 0;
tp = PropertyType.Unknown;
bd = 0;
bt = 0.0F;
rnt = 0D;
}
To create an array of objects, you can declare an array variable and use the square
brackets to specify its size. Here is an example:
public static class Exercise
{
static void Main(string[] args)
{
Employee[] StaffMembers = new Employee[3];
return 0;
}
}
return 0;
}
}
If you create an array like this, you can then access each member using its index,
allocate memory for it using the new operator, then access each of its fields, still using
its index, to assign it the desired value. Here is an example:
public static class Exercise
{
static void Main(string[] args)
{
var StaffMembers = new Employee[3];
return 0;
}
}
As an alternative, you can also initialize each member of the array when creating it. To
do this, before the semi-colon of creating the array, open the curly brackets, allocate
memory for each member and specify the values of each field. To do this, you must use
a constructor that takes each member you want to initialize, as argument. Here is an
example:
using System;
public Employee()
{
}
return 0;
}
}
If using the var keyword and a constructor to initialize the array, you can omit calling
the name of the class before the square brackets. Here is an example:
public static class Exercise
{
static void Main(string[] args)
{
var StaffMembers = new[]
{
new Employee(20204, "Harry Fields",
EmploymentStatus.FullTime, 16.85),
new Employee(92857, "Jennifer Almonds",
EmploymentStatus.FullTime, 22.25),
new Employee(42963, "Sharon Culbritt",
EmploymentStatus.PartTime, 10.95)
};
return 0;
}
}
After creating and initializing the array, you can use it as you see fit. For example, you
may want to display its values to the user. You can access any member of the array by
its index, then use the same index to get its field(s) and consequently its (their)
value(s). Here is an example:
public static class Exercise
{
static void Main(string[] args)
{
var StaffMembers = new Employee[]
{
new Employee(20204, "Harry Fields",
EmploymentStatus.FullTime, 16.85),
new Employee(92857, "Jennifer Almonds",
EmploymentStatus.FullTime, 22.25),
new Employee(42963, "Sharon Culbritt",
EmploymentStatus.PartTime, 10.95)
};
Console.WriteLine("Employee Record");
Console.WriteLine("---------------------------");
Console.WriteLine("Employee #: {0}",
StaffMembers[2].EmployeeNumber);
Console.WriteLine("Full Name: {0}",
StaffMembers[2].EmployeeName);
Console.WriteLine("Status: {0}", StaffMembers[2].Status);
Console.WriteLine("Hourly Wage {0}",
StaffMembers[2].HourlySalary);
return 0;
}
}
Once again, remember that the index you use must be higher than 0 but lower than the
number of members - 1. Otherwise, the compiler would throw an
IndexOutRangeException exception.
In the same way, you can use a for loop to access all members of the array using their
index. Here is an example:
public static class Exercise
{
static void Main(string[] args)
{
var StaffMembers= new Employee[]
{
new Employee(20204, "Harry Fields",
EmploymentStatus.FullTime, 16.85),
new Employee(92857, "Jennifer Almonds",
EmploymentStatus.FullTime, 22.25),
new Employee(42963, "Sharon Culbritt",
EmploymentStatus.PartTime, 10.95)
};
Console.WriteLine("Employees Records");
Console.WriteLine("==========================");
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Employee #: {0}",
StaffMembers[i].EmployeeNumber);
Console.WriteLine("Full Name: {0}",
StaffMembers[i].EmployeeName);
Console.WriteLine("Status: {0}", StaffMembers[i].Status);
Console.WriteLine("Hourly Wage {0}",
StaffMembers[i].HourlySalary);
Console.WriteLine("---------------------------");
}
return 0;
}
}
To access each member of the array, you can use the foreach operator that allows you
to use a name for each member and omit the square brackets. Here is an example:
Console.WriteLine("Employees Records");
Console.WriteLine("==========================");
foreach(var Member in StaffMembers)
{
Console.WriteLine("Employee #: {0}", Member.EmployeeNumber);
Console.WriteLine("Full Name: {0}", Member.EmployeeName);
Console.WriteLine("Status: {0}", Member.Status);
Console.WriteLine("Hourly Wage {0}", Member.HourlySalary);
Console.WriteLine("---------------------------");
}
return 0;
}
}
Console.WriteLine("Properties Listing");
Console.WriteLine("---------------------------------------------");
for (int i = 0; i < 8; i++)
{
Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}",
Properties[i].PropertyNumber,
Properties[i].TypeOfProperty,
Properties[i].Bedrooms,
Properties[i].Bathrooms,
Properties[i].MonthlyRent);
}
Console.WriteLine("=============================================");
}
}
}
Introduction
Like a primitive type, an array of objects can be made a field of a class. You can
primarily declare the array and specify its size. Here is an example:
public class CompanyRecords
{
Employee[] Employees = new Employee[2];
}
After doing this, you can then initialize the array from the index of each member.
Alternatively, as we saw for field arrays of primitive types, you can declare the array in
To initialize the array, remember that each member is a value that must be allocated on
the heap. Therefore, apply the new operator on each member of the array to allocate its
memory, and then initialize it. Here is an example:
public class CompanyRecords
{
Employee[] Employees;
public CompanyRecords()
{
Employees = new Employee[2];
If the class used as field has an appropriate constructor, you can use it to initialize each
member of the array. Here is an example:
public class CompanyRecords
{
Employee[] Employees;
public CompanyRecords()
{
Employees = new Employee[]
{
new Employee(70128, "Justine Hearson",
EmploymentStatus.PartTime, 10.62),
new Employee(24835, "Bertha Hack",
EmploymentStatus.FullTime, 18.94),
new Employee(70128, "Frank Dennison",
EmploymentStatus.Seasonal, 12.48),
new Employee(24835, "Jeffrey Arndt",
EmploymentStatus.PartTime, 16.05),
};
}
}
Once you have created and initialized the array, you can use it as you see fit, such as
displaying its values to the user. You must be able to access each member of the array,
using its index. Once you have accessed member, you can get to its fields or properties.
Here is an example:
C# 3.0 Practical Learning 543
using System;
public Employee()
{
}
public CompanyRecords()
C# 3.0 Practical Learning 544
{
Employees = new Employee[]
{
new Employee(70128, "Justine Hearson",
EmploymentStatus.PartTime, 10.62),
new Employee(24835, "Bertha Hack",
EmploymentStatus.FullTime, 18.94),
new Employee(70128, "Frank Dennison",
EmploymentStatus.Seasonal, 12.48),
new Employee(24835, "Jeffrey Arndt",
EmploymentStatus.PartTime, 16.05),
};
}
return 0;
}
}
As done for an array of a primitive type, you can pass an array of objects as arguments.
You follow the same rules we reviewed; that is, in the parentheses of a method, enter
the class name, the empty square brackets, and the name of the argument. Here is an
example:
public class CompanyRecords
{
public CompanyRecords(Employee[] Employees)
{
}
}
You can then access each member of the argument and do what you judge necessary.
For example, you can display the values that the argument is holding. To call a method
that takes an array of objects, in its parentheses, just enter the name of the array. Here
is an example:
public class CompanyRecords
{
public CompanyRecords(Employee[] Employees)
{
Employees = new Employee[]
{
new Employee(70128, "Justine Hearson",
EmploymentStatus.PartTime, 10.62),
new Employee(24835, "Bertha Hack",
EmploymentStatus.FullTime, 18.94),
new Employee(70128, "Frank Dennison",
EmploymentStatus.Seasonal, 12.48),
new Employee(24835, "Jeffrey Arndt",
EmploymentStatus.PartTime, 16.05),
};
}
}
An array of objects can be returned from a method. To indicate this when defining the
method, first type the name of the class followed by square brackets. Here is an
example:
public class CompanyRecords
{
public Employee[] RegisterEmployees()
{
}
}
In the body of the method, you can take care of any assignment you want. The major
rule to follow is that, before exiting the method, you must return an array of the class
indicated on the left side of the method name.
To use the method, you can simply call. If you want, since the method returns an array,
you can retrieve that series and store it in a local array value for later use. Here is an
example:
using System;
public Employee()
{
}
return 0;
}
}
1. To apply what we learned in the last few sections, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RentalProperties2
{
public class Program
{
private static void ShowProperties(RentalProperty[] Properties)
{
Console.WriteLine("Properties Listing");
Console.WriteLine("=============================================");
Console.WriteLine("Prop # Property Type Beds Baths Monthly
Rent");
Console.WriteLine("---------------------------------------------");
for (int i = 0; i < 8; i++)
{
Console.WriteLine("{0}\t{1}\t{2} {3:F}{4,12}",
Properties[i].PropertyNumber,
Properties[i].TypeOfProperty,
Properties[i].Bedrooms,
Properties[i].Bathrooms,
Properties[i].MonthlyRent);
}
Console.WriteLine("=============================================");
}
return HousesToRent;
}
ShowProperties(Properties);
}
}
}
Introduction
While a regular method can be used to return an array, you can use the features of a
delegate to return an array of methods or to take an array of methods as arguments. Of
course before proceeding, you must first create the necessary delegate. Here is an
example:
using System;
Before creating the array, you must first know or have the methods you would be
referring to. These methods must have a similar signature. This means that they must
return the same type of value, they must have the same number of arguments and they
must have the same type(s) of argument(s), if any. Here are examples of such
functions:
using System;
An Array of Delegates
To create an array of delegates, declare a normal array as we have done so far. You can
initialize each member using its index and calling the corresponding method. This can be
done as follows:
using System;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Diameter: {0}", D);
Console.WriteLine("Circumference: {0}", C);
Console.WriteLine("Area: {0}\n", A);
return 0;
}
}
double D = Calc[0](R);
double C = Calc[1](R);
double A = Calc[2](R);
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Diameter: {0}", D);
Console.WriteLine("Circumference: {0}", C);
Console.WriteLine("Area: {0}\n", A);
return 0;
}
}
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Diameter: {0}", Calc[0](R));
Console.WriteLine("Circumference: {0}", Calc[1](R));
Console.WriteLine("Area: {0}\n", Calc[2](R));
return 0;
}
}
Introduction
The arrays we used so far were made of a uniform series, where all members consisted
of a simple list, like a column of names on a piece of paper. Also, all items fit in one list.
This type of array is referred to as one-dimensional.
In some cases, you may want to divide the list in delimited sections. For example, if you
create a list of names, you may want part of the list to include family members and
another part of the list to include friends. Instead of creating a second list, you can add
a second dimension to the list. In other words, you would create a list of a list, or one
list inside of another list, although the list is still made of items with common
characteristics.
A multidimensional array is a series of arrays so that each arrays contains its own sub-
array(s).
namespace DepartmentStore3
{
public class Program
{
static void Main(string[] args)
{
long ItemID = 0;
string Description = "Unknown";
double Price = 0.00D;
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
C# 3.0 Practical Learning 554
}
}
}
The most basic multidimensional array is made of two dimensions. This is referred to as
two-dimensional. To create a two-dimensional array, declare the array variable as we
have done so far but add a comma in the square brackets. The formula you would use
is:
DataType[,] VariableName;
The pair of brackets is empty but must contain a comma. There are various ways you
can initialize a two-dimensional array. If you are declaring the array variable but are not
ready to initialize it, use the following formula:
DataType[,] VariableName = new DataType[Number1,Number2];
Either way, in the right pair of square brackets, enter two integers separated by a
comma. Here is an example:
using System;
return 0;
}
}
In our declaration, the Members variable contains two lists. Each of the two lists
contains 4 elements. This means that the first list contains 4 elements and the second
list contains 4 elements. Therefore, the whole list is made of 8 elements (2 * 4 = 8).
Because the variable is declared as a string, each of the 8 items must be a string.
You can also create a two-dimensional array that takes more than two lists, such as 3,
4, 5 or more. Here is an example:
return 0;
}
}
This time, the variable has 5 lists and each list contains 8 elements. This means that the
whole variable contains 5 * 8 = 40 elements.
If you want to declare the array variable using the first formula where you don't know
the sizes of the lists, you must use the data type of the array and you can omit the right
square brackets. Here is an example:
using System;
return 0;
}
}
In this case also, remember that you need the square brackets. If you use the var
keyword, you don't need the left square brackets but, in the right square brackets, you
must specify the sizes.
You can initialize an array variable when declaring it. To do this, on the right side of the
declaration, before the closing semi-colon, type an opening and a closing curly brackets.
Inside of the brackets, include a pair of an opening and a closing curly brackets for each
internal list of the array. Then, inside of a pair of curly brackets, provide a list of the
values of the internal array, just as you would do for a one-dimensional array. Here is an
example:
using System;
return 0;
}
}
return 0;
}
}
If you use this technique to initialize an array, you can omit specifying the dimension of
the array. That is, you can remove the numbers in the right square brackets. Here is an
example:
using System;
return 0;
}
}
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
}
}
}
return 0;
}
}
You can use this same technique to retrieve the value of each member of the array.
Here is an example:
using System;
Console.WriteLine(Members[0, 0]);
Console.WriteLine(Members[0, 1]);
Console.WriteLine(Members[0, 2]);
Console.WriteLine(Members[0, 3]);
Console.WriteLine(Members[1, 0]);
Console.WriteLine(Members[1, 1]);
return 0;
}
}
return 0;
}
}
To apply a foreach operator, access only each member of the internal list. Here is an
example:
using System;
return 0;
}
}
namespace DepartmentStore3
{
public class Program
{
static void Main(string[] args)
{
long ItemID = 0;
string Description = "Unknown";
double Price = 0.00D;
// Order Processing
try
{
Console.Write("Enter Item Number: ");
ItemID = long.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine(
"Invalid Number - The program will terminate\n");
}
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
}
}
}
4. Execute the application again and enter a different item number. Here is an
example:
Enter Item Number: 273644
C# 3.0 Practical Learning 562
Receipt
Item Number: 273644
Description: Unknown
Unit Price: $0.00
Multidimensional Arrays
Introduction
Beyond two dimensions, you can create an array variable that represents various lists,
and each list contains various internal lists, and each internal list contains its own
elements. This is referred to as a multidimensional array. One of the rules you must
follow is that, as always, all members of the array must be of the same type.
To create a multidimensional array, add as many commas in the square brackets as you
judge them necessary. If you only want to declare the variable without indicating the
actual number of lists, you can specify the data type followed by square brackets and
the commas. Here is an example that represents a three-dimensional array that is not
initialized:
using System;
return 0;
}
}
If you know the types of members the array will use, you can use the assignment
operator and specify the numbers of lists in the square brackets. Here is an example:
using System;
return 0;
}
}
In this case, you can use the var keyword on the left side of the name of the variable:
return 0;
}
}
In this example, we are creating 2 groups of items. Each of the two groups is made of
three lists. Each list contains 5 numbers. As a result, the array contains 2 * 3 * 5 = 30
members.
As always, there are various ways you can initialize an array. To initialize a
multidimensional array when creating it, you use an opening and a closing curly brackets
for each list but they must be nested. The most external pair of curly brackets
represents the main array. Inside of the main curly brackets, the first nested curly
brackets represent a list of the first dimension. Inside of those brackets, you use another
set curly brackets to represent a list that would be nested. You continue this up to the
most internal array. Then, in that last set, you initialize the members of the array by
specifying their values. Here is an example:
using System;
return 0;
}
}
To access a member of a multidimensional array, type the name of the array followed by
the opening square bracket, followed by the 0-based first dimension, followed by a
Number[0, 0, 0] = 12.44;
Number[0, 0, 1] = 525.38;
Number[0, 0, 2] = -6.28;
Number[0, 0, 3] = 2448.32;
Number[0, 0, 4] = 632.04;
Number[0, 1, 0] = -378.05;
Number[0, 1, 1] = 48.14;
Number[0, 1, 2] = 634.18;
Number[0, 1, 3] = 762.48;
Number[0, 1, 4] = 83.02;
Number[0, 2, 0] = 64.92;
Number[0, 2, 1] = -7.44;
Number[0, 2, 2] = 86.74;
Number[0, 2, 3] = -534.60;
Number[0, 2, 4] = 386.73;
Number[1, 0, 0] = 48.02;
Number[1, 0, 1] = 120.44;
Number[1, 0, 2] = 38.62;
Number[1, 0, 3] = 526.82;
Number[1, 0, 4] = 1704.62;
Number[1, 1, 0] = 56.85;
Number[1, 1, 1] = 105.48;
Number[1, 1, 2] = 363.31;
Number[1, 1, 3] = 172.62;
Number[1, 1, 4] = 128.48;
Number[1, 2, 0] = 906.68;
Number[1, 2, 1] = 47.12;
Number[1, 2, 2] = -166.07;
Number[1, 2, 3] = 4444.26;
Number[1, 2, 4] = 408.62;
return 0;
}
}
This is the same approach you can use to access each member of the array to check or
retrieve its value. Here are examples:
using System;
return 0;
}
}
Number[0][1][0] = -378.05
Number[0][1][1] = 48.14
Number[0][1][2] = 634.18
C# 3.0 Practical Learning 566
Number[0][1][3] = 762.48
Number[0][1][4] = 83.02
Number[0][2][0] = 64.92
Number[0][2][1] = -7.44
Number[0][2][2] = 86.74
Number[0][2][3] = -534.6
Number[0][2][4] = 386.73
Number[1][0][0] = 48.02
Number[1][0][1] = 120.44
Number[1][0][2] = 38.62
Number[1][0][3] = 526.82
Number[1][0][4] = 1704.62
Number[1][1][0] = 56.85
Number[1][1][1] = 105.48
Number[1][1][2] = 363.31
Number[1][1][3] = 172.62
Number[1][1][4] = 128.48
Number[1][2][0] = 906.68
Number[1][2][1] = 47.12
Number[1][2][2] = -166.07
Number[1][2][3] = 4444.26
Number[1][2][4] = 408.62
Since the lists are nested, if you want to use loops to access the members of the array,
you can nest the for loops to incrementally access the values. Here is an example:
using System;
Number[0, 0, 0] = 12.44;
Number[0, 0, 1] = 525.38;
Number[0, 0, 2] = -6.28;
Number[0, 0, 3] = 2448.32;
Number[0, 0, 4] = 632.04;
Number[0, 1, 0] = -378.05;
Number[0, 1, 1] = 48.14;
Number[0, 1, 2] = 634.18;
Number[0, 1, 3] = 762.48;
Number[0, 1, 4] = 83.02;
Number[0, 2, 0] = 64.92;
Number[0, 2, 1] = -7.44;
Number[0, 2, 2] = 86.74;
Number[0, 2, 3] = -534.60;
Number[0, 2, 4] = 386.73;
Number[1, 0, 0] = 48.02;
Number[1, 0, 1] = 120.44;
Number[1, 0, 2] = 38.62;
Number[1, 0, 3] = 526.82;
Number[1, 0, 4] = 1704.62;
C# 3.0 Practical Learning 567
Number[1, 1, 0] = 56.85;
Number[1, 1, 1] = 105.48;
Number[1, 1, 2] = 363.31;
Number[1, 1, 3] = 172.62;
Number[1, 1, 4] = 128.48;
Number[1, 2, 0] = 906.68;
Number[1, 2, 1] = 47.12;
Number[1, 2, 2] = -166.07;
Number[1, 2, 3] = 4444.26;
Number[1, 2, 4] = 408.62;
return 0;
}
}
. . . No Change
if (Value % 5 == 0)
Console.WriteLine();
}
return 0;
}
}
To use a foreach operator, access only each member to get to it. Here is an example:
using System;
. . . No Change
return 0;
}
}
Introduction
Like an array of a primitive type, a multidimensional array can be made a field of a class.
You can primarily declare it without initializing it. Here is an example:
public class TriangleInCoordinateSystem
{
private int[,] Points;
}
This indicates a two-dimensional array field: the array will contain two lists but we don't
know (yet) how many members each array will contain. Therefore, if you want, when
You can also use a method of the class or a constructor to indicate the size of the array.
Here is an example:
public class TriangleInCoordinateSystem
{
private int[,] Points;
public TriangleInCoordinateSystem()
{
Points = new int[3, 2];
}
}
To initialize the array, you can access each member using the square brackets as we
saw in the previous sections. Here is an example:
public class TriangleInCoordinateSystem
{
private int[,] Points;
public TriangleInCoordinateSystem()
{
Points = new int[3, 2];
After initializing the array, you can use it as you see fit. For example, you can display its
values to the user. Here is an example:
using System;
public TriangleInCoordinateSystem()
{
Points = new int[3, 2];
Triangle.ShowPoints();
return 0;
}
}
A multidimensional array can be passed as argument. When creating the method, in its
parentheses, enter the data type followed by the square brackets. In the square
brackets, enter one comma for a two-dimensional array, two or more commas, as
necessary, for a three-dimensional arrays as necessary. Here is an example:
public class TriangleInCoordinateSystem
{
public void ShowPoints(int[,] Coords)
{
}
}
When defining the method, in its body, you can use the array as you see fit, such as
displaying its values. Here is an example:
public class TriangleInCoordinateSystem
{
public void ShowPoints(int[,] Coords)
{
Console.WriteLine("Coordinates of the Triangle");
Console.WriteLine("A({0}, {1})", Coords[0, 0], Coords[0, 1]);
Console.WriteLine("B({0}, {1})", Coords[1, 0], Coords[1, 1]);
Console.WriteLine("C({0}, {1})", Coords[2, 0], Coords[2, 1]);
}
}
Triangle.CreateTriangle(ref Coordinates);
Triangle.ShowPoints(Coordinates);
return 0;
}
}
You can return a multi-dimensional array from a method. When creating the method,
before its name, specify the data type followed by square brackets. In the square
brackets, enter the necessary number of commas. Here is an example:
using System;
In the body of the method, you can do what you want but, before exiting it, you must
return an array of the same type that was created. When calling the method, you can
assign it to an array of the same type it returns. Here is an example:
using System;
Points[0, 0] = 6; // A(x, )
Points[0, 1] = 1; // A( , y)
Points[1, 0] = 2; // B(x, )
Points[1, 1] = 3; // B( , y)
Points[2, 0] = 1; // C(x, )
Points[2, 1] = 4; // C( , y)
return Points;
}
Coordinates = Triangle.CreateTriangle();
Triangle.ShowPoints(Coordinates);
return 0;
}
}
As done for primitive data types, you can create a multi-dimensional array where each
member is of a class type. Of course you can use an existing class or you must first
create a class. Here is an example:
public class Point
{
private int XCoord;
private int YCoord;
public int x
{
get { return XCoord; }
set { XCoord = value; }
}
public int y
{
get { return YCoord; }
set { YCoord = value; }
}
}
To create a multidimensional array of objects without initializing it, you can use the
following formula:
ClassName[,] VariableName;
If you know the number of instances of the class that the array will use, you can use the
following formula:
ClassName[,] VariableName = new ClassName[Number1,Number2];
The ClassName factor is the name of the class that will make up each member of the
array. The other sections follow the same rules we reviewed for the primitive types. For
example, you can create an array without allocating memory for it as follows:
public static class Exercise
{
static int Main(string[] args)
{
Point[,] Line;
return 0;
}
}
return 0;
}
}
This declaration creates a two-dimensional array of two Point objects: The array
contains two lists and each list contains two Points.
To initialize a multidimensional array of objects, you can access each array member
using its index, allocate memory for it using the new operator. After allocating memory
for the member, you can then access its fields or properties to initialize it. Here is an
example:
using System;
public int x
{
get { return XCoord; }
set { XCoord = value; }
}
public int y
{
get { return YCoord; }
set { YCoord = value; }
}
}
return 0;
}
}
public Point()
{
}
public int x
{
get { return XCoord; }
set { XCoord = value; }
}
public int y
{
get { return YCoord; }
set { YCoord = value; }
}
}
return 0;
}
}
Console.WriteLine("Line =-=");
Console.WriteLine("From A({0}, {1}) to B({2}, {3})",
Line[0, 0].x, Line[0, 0].y,
Line[0, 1].x, Line[0, 1].y);
return 0;
}
}
You can also use a loop to access the members of the array. To do this, create a first
for loop that stops at the first dimension of the array - 1. Then, inside of a first for
loop, nest a for loop for each subsequent dimension. Here is an example:
public static class Exercise
{
public static int Main(string[] args)
{
var Line = new Point[,]
{
{
new Point(-3, 8), new Point(4, -5)
}
};
To apply a foreach operator, access only each member of the internal list. Here is an
example:
public static class Exercise
C# 3.0 Practical Learning 577
{
static int Main(string[] args)
{
var Line = new Point[,]
{
{
new Point(-3, 8), new Point(4, -5)
}
};
return 0;
}
}
Introduction
As done for primitive types, a multidimensional array of objects can be made a field of a
class. You can declare the array without specifying its size. Here is an example:
public class Triangle
{
public Point[,] Vertices;
}
If you know the dimensions that the array will have, you can specify them using the new
operator at the same time you are creating the field. Here is an example:
public class Triangle
{
public Point[,] Vertices = new Point[3,2];
}
This creation signals a multidimensional array of Point objects. It will consist of three
lists and each list will contain two Point objects
To initialize the array, access each member by its index to allocate memory for it. Once
you get the member, you access each one of its fields or properties and initialize it with
the desired value. Here is an example:
public class Triangle
{
public Point[,] Vertices = new Point[3, 2];
public Triangle()
{
Vertices[0, 0] = new Point(); // Point A(x, y)
Vertices[0, 0].x = -2; // A(x, )
Vertices[0, 0].y = -4; // A( , y)
Vertices[1, 0] = new Point(); // Point B(x, y)
Vertices[1, 0].x = 3; // B(x, )
If the class is equipped with the right constructor, you can use it to initialize each
member of the array.
Once the array is ready, you can access each members using its index and manipulate
it. For example you can display its value(s) to the user. Here is an example:
using System;
public Point()
{
}
public int x
{
get { return XCoord; }
set { XCoord = value; }
}
public int y
{
get { return YCoord; }
set { YCoord = value; }
}
}
public Triangle()
{
Vertices[0, 0] = new Point(); // Point A(x, y)
Vertices[0, 0].x = -2; // A(x, )
Vertices[0, 0].y = -4; // A( , y)
Vertices[1, 0] = new Point(); // Point B(x, y)
Vertices[1, 0].x = 3; // B(x, )
Vertices[1, 0].y = 5; // B( , y)
Vertices[2, 0] = new Point(); // Point C(x, y)
Vertices[2, 0].x = 6; // C(x, )
Vertices[2, 0].y = -2; // C( , y)
}
return 0;
}
}
In the body of the method, use the array as you we have done so far. You can access its
members to get to its values. Here are examples:
public class Triangle
{
public void Create(Point[,] Points)
{
Points[0, 0] = new Point(); // Point A(x, y)
Points[0, 0].x = -2; // A(x, )
Points[0, 0].y = -4; // A( , y)
Points[1, 0] = new Point(); // Point B(x, y)
Points[1, 0].x = 3; // B(x, )
Points[1, 0].y = 5; // B( , y)
Points[2, 0] = new Point(); // Point C(x, y)
Points[2, 0].x = 6; // C(x, )
Points[2, 0].y = -2; // C( , y)
}
Tri.Create(Vertices);
Tri.Identify(Vertices);
return 0;
}
}
Remember that an array passed as argument is in fact passed by reference. You can
indicate this by preceding it with the ref keyword.
A method can return a multidimensional array of objects. If you are creating the
method, before its name, type the name of the class followed by square brackets. Inside
the square brackets, type the desired number of commas to indicate the dimension of
the returned value. Here is an example:
public class Triangle
{
public Point[,] Create()
{
}
}
After implementing the method, before exiting it, make sure it returns the type of array
that it was indicated to produce. Here is an example:
using System;
public Point()
{
}
public int y
{
get { return YCoord; }
set { YCoord = value; }
}
}
return Points;
}
return 0;
}
}
Each of the square brackets is used in any of the ways we have introduced arrays so far.
This means that the first square bracket can be used as its own one-dimensional array
or as a multi-dimensional array. Here is an example:
string[2][5] Members;
This declares a variable that represents two arrays and each array internally contains 5
arrays. Because each pair of square brackets is its own array, it can be used to create its
own array with its own multidimensional array. Here is an example that creates a
multidimensional array in the first dimension:
string[2,4][5] Members;
In the same way, the second square bracket can be used as a single or a
multidimensional array. Here is an example:
string[2,4][5,12,8] Members;
namespace DepartmentStore4
{
public class Program
{
static int Main(string[] args)
{
long ItemID = 0;
string Description = "Unknown";
double Price = 0.00D;
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
}
}
}
When declaring a jagged array, you can allocate memory for it using the new operator
followed by the data type of the array and the same combination of square brackets
used to the left of the assignment operator. The first pair of square brackets on the right
side of the assignment operator must contain the external dimension of the array. The
second pair of square brackets must be left empty. Here is an example:
using System;
To initialize a jagged array, when declaring the variable, on the right side of the second
pair of square brackets, provide an opening and a closing curly brackets, then create
each list in its own pair of curly brackets. At the beginning of each list, you must allocate
memory for the list with the new operator. Here is an example:
using System;
return 0;
}
}
If you initialize the array this way, you can omit specifying the dimension of the external
array. With a jagged array, you can also initialize its internal array individually. To do
this, access each internal array by its zero-based index. Here is an example:
public class Exercise
{
static int Main(string[] args)
{
string[][] Members = new string[2][];
return 0;
}
}
namespace DepartmentStore4
{
public class Program
{
static int Main(string[] args)
{
long ItemID = 0;
string Description = "Unknown";
double Price = 0.00D;
long[][][] ItemNumber =
new long[][][]
{
new long[][]
{
new long[]{947783, 934687, 973947, 987598, 974937},
new long[]{743765, 747635, 765473, 754026, 730302}
},
new long[][]
{
new long[]{209579, 267583, 248937, 276057, 267945},
new long[]{ 409579, 467583, 448937, 476057, 467945}
}
};
C# 3.0 Practical Learning 585
string[][][] ItemName =
new string[][][]
{
new string[][]
{
new string[]
{
"Double-faced wool coat",
"Floral Silk Tank Blouse",
"Push Up Bra",
"Chiffon Blouse",
"Bow Belt Skirtsuit"
},
new string[]
{
"Cable-knit Sweater",
"Jeans with Heart Belt",
"Fashionable mini skirt",
"Double Dry Pants",
"Romantic Flower Dress"
}
},
new string[][]
{
new string[]
{
"Cotton Polo Shirt",
"Pure Wool Cap",
"Striped Cotton Shirt",
"Two-Toned Ribbed Crewneck",
"Chestnut Italian Shoes"
},
new string[]
{
"Under Collar and Placket Jacket",
"Country Coat Rugged Wear",
"Carpenter Jeans",
"Double-Cushion Tennis Shoes",
"Stitched Center-Bar Belt"
}
}
};
double[][][] UnitPrice =
new double[2][][]
{
new double[][]
{
new double[]
{ 275.25, 180.00, 50.00, 265.00, 245.55 },
new double[]
{ 45.55, 25.65, 34.55, 28.55, 24.95 }
},
new double[][]
{
new double[]
{ 45.75, 25.00, 65.55, 9.75, 165.75 },
new double[]
{ 265.15, 35.55, 24.95, 48.75, 32.50 }
C# 3.0 Practical Learning 586
}
};
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
}
}
}
As done for a multidimensional array, each member of a jagged array can be accessed
with a multiple index, depending on how the array was created. Both the external and
the internal lists are zero-based. Here is an example:
using System;
return 0;
}
}
You can also use some loops to access each member of the array. Here is an example:
C# 3.0 Practical Learning 587
using System;
return 0;
}
}
If you want to use a foreach operator, you must access each array by its index. The
external array can be accessed using a-zero based index and remember that you are
accessing a whole array. Here is an example:
using System;
return 0;
}
}
namespace DepartmentStore4
{
public class Program
{
static int Main(string[] args)
{
long ItemID = 0;
string Description = "Unknown";
double Price = 0.00D;
string Category = "Category";
long[][][] ItemNumber =
new long[][][]
{
new long[][]
{
new long[]{947783, 934687, 973947, 987598, 974937},
new long[]{743765, 747635, 765473, 754026, 730302}
},
new long[][]
{
new long[]{209579, 267583, 248937, 276057, 267945},
new long[]{ 409579, 467583, 448937, 476057, 467945}
}
};
string[][][] ItemName =
new string[][][]
{
new string[][]
{
new string[]
{
"Double-faced wool coat",
C# 3.0 Practical Learning 589
"Floral Silk Tank Blouse",
"Push Up Bra",
"Chiffon Blouse",
"Bow Belt Skirtsuit"
},
new string[]
{
"Cable-knit Sweater",
"Jeans with Heart Belt",
"Fashionable mini skirt",
"Double Dry Pants",
"Romantic Flower Dress"
}
},
new string[][]
{
new string[]
{
"Cotton Polo Shirt",
"Pure Wool Cap",
"Striped Cotton Shirt",
"Two-Toned Ribbed Crewneck",
"Chestnut Italian Shoes"
},
new string[]
{
"Under Collar and Placket Jacket",
"Country Coat Rugged Wear",
"Carpenter Jeans",
"Double-Cushion Tennis Shoes",
"Stitched Center-Bar Belt"
}
}
};
double[][][] UnitPrice =
new double[2][][]
{
new double[][]
{
new double[]
{ 275.25, 180.00, 50.00, 265.00, 245.55 },
new double[]
{ 45.55, 25.65, 34.55, 28.55, 24.95 }
},
new double[][]
{
new double[]
{ 45.75, 25.00, 65.55, 9.75, 165.75 },
new double[]
{ 265.15, 35.55, 24.95, 48.75, 32.50 }
}
};
// Order Processing
try
{
Console.Write("Enter Item Number: ");
ItemID = long.Parse(Console.ReadLine());
}
C# 3.0 Practical Learning 590
catch (FormatException)
{
Console.WriteLine(
"Invalid Number - The program will terminate\n");
}
Console.WriteLine("Receipt");
Console.WriteLine("Item Number: {0}", ItemID);
Console.WriteLine("Description: {0}", Description);
Console.WriteLine("Unit Price: {0:C}\n", Price);
}
}
}
Overview
In the previous lessons, we saw how to create and initialize arrays. To assist with the
use and management of arrays, you can combine the array features of the C#
language and support from the .NET Framework. To support arrays, the .NET
Framework provides a class of the same name. The Array class is defined in the System
namespace of the System.dll assembly.
When you create an array, you are in fact declaring a variable of type Array. Based on
this, since an array variable is an object of a class type, you can use the characteristics
of the Array class to create an array and/or to manipulate the values stored in the
variable. You can create an array using any of the techniques we saw in the previous
lessons, or you can use the Array class.
To assist you with creating an array, the Array class is equipped with the
CreateInstance() method that comes in various versions. To create a one-dimensional
array whose members are zero-based, you can use the following version:
public static Array CreateInstance(Type elementType, int length);
The first argument is used to specify the type of array you want to create. Since it is
declared as Type, you can use the typeof operator to cast your type.
The second argument specifies the number of members of the array. Using the Array
class, you can create an array as follows:
using System;
return 0;
}
}
You can also use the var keyword to declare the variable:
using System;
return 0;
}
}
We saw that if you declare a variable for an array but don't initialize it, you must specify
the number of elements of the array. This number is passed inside the second pair of
square brackets, as a constant integer. Here is an example:
using System;
return 0;
}
}
If you use the Array class to create an array, you must pass this constant integer as the
second argument of the CreateInstance() method from the the above version. Here is
an example:
using System;
return 0;
}
}
If the array exists already, that is, if you have already created the array or you are using
an array created by someone else, to find out the number of items it contains, you can
access its Length property. Therefore, the length of an array is the number of elements
it contains.
Alternatively, you can call the Array.GetLength() method. Its syntax is:
public int GetLength(int dimension);
For a one-dimensional array, you must pass the argument as 0. This method returns a
32-bit integer that represents the number of items in the array.
C# 3.0 Practical Learning 594
The Rank of an Array
We have seen that the square brackets are used to specify that you are declaring an
array. If you are creating a one-dimensional array, we saw that you could type a
number in the square bracket. If you are creating a two-dimensional array, you type two
numbers separated by a comma in the second pair of square brackets. Each number,
whether it is one, two, or more is a placeholder for what is referred to a dimension. In
other words, a one dimensional array has a dimension of one. A two-dimensional array
has a dimension of 2.
To find out the dimension of an array, the Array class provides the Rank property.
Therefore, to know the dimension of an existing array, you can access its Rank.
Before using a class, it must have values or members in it. In the previous lesson, we
saw that, to initialize an array, you open the curly brackets and list its members
separated by commas, or you could access each member and assign it the desired
value. To support the ability to add members to an array, the Array is equipped with a
method named SetValue() that comes in different versions. To add a new item to a
the type of array we have used so far, you can call the following version of the
Array.SetValue() method:
The first argument is the value to add to the list. The second argument is the index of
the member to be added. The first item has index 1; the second item has index 2, and
so on. Here is an example:
using System;
Numbers.SetValue(7628.937, 0);
Numbers.SetValue(6.48, 1);
Numbers.SetValue(574.9, 2);
Numbers.SetValue(293749.064, 3);
Numbers.SetValue(0.70257, 4);
return 0;
}
}
We indicated that whenever you create an array, you are in fact declaring an instance of
the Array class. Therefore, even if you create an array using the square bracket formula
Numbers.SetValue(7628.937, 0);
Numbers.SetValue(6.48, 1);
Numbers.SetValue(574.9, 2);
Numbers.SetValue(293749.064, 3);
Numbers.SetValue(0.70257, 4);
return 0;
}
}
Once the array is initialized, you can access its members and do what you want with
their values. To support the ability to retrieve the value of a member of an array, the
Array class is equipped with a method named GetValue that is overloaded with a
version corresponding to each version of the CreateInstance() and the SetValue()
methods. For example, to access the values stored in a one-dimensional array, you can
call call this version:
public object GetValue(int index);
The index argument is the zero-based index of the member whose value you want to
access. Here is an example:
using System;
Numbers.SetValue(7628.937, 0);
Numbers.SetValue(6.48, 1);
Numbers.SetValue(574.9, 2);
Numbers.SetValue(293749.064, 3);
Numbers.SetValue(0.70257, 4);
return 0;
}
}
Just as you can access one member of the array, you can access any member using its
index. Here is an example that uses a for loop and the Length property to know the
number of members of an array:
using System;
Numbers.SetValue(7628.937, 0);
Numbers.SetValue(6.48, 1);
Numbers.SetValue(574.9, 2);
Numbers.SetValue(293749.064, 3);
Numbers.SetValue(0.70257, 4);
return 0;
}
}
If using the foreach operator, you don't need the GetValue() method. Here is an
example:
using System;
Numbers.SetValue(7628.937, 0);
Numbers.SetValue(6.48, 1);
Numbers.SetValue(574.9, 2);
Numbers.SetValue(293749.064, 3);
Numbers.SetValue(0.70257, 4);
return 0;
}
}
Multidimensional Arrays
Two-Dimensional Arrays
C# 3.0 Practical Learning 597
The Array class supports the creation of any of the types of arrays we saw in the
previous lessons. In the previous lesson, we saw that a two-dimensional array was an
array made of two lists:
using System;
return 0;
}
}
To create such an array using the Array class, you can use the following version of the
Array.CreateInstance() method:
The first argument is the type of array you want to create. The second argument is the
length of the first list. The third argument is the length of the second list. Here is an
example of using it:
using System;
return 0;
}
}
To specify the values of a two-dimensional array, you can use the following version of
the Array.SetValue() method:
public void SetValue(object value, int index1, int index2)
The first argument is the value you want to add. The second argument is the index of
the list. The second argument is the index of the element that is being added. Here is an
example:
using System;
return 0;
}
}
Just as mentioned for the one-dimensional array, you can use the square brackets to
create the array but call the SetValue() method to specify the value of each element.
This method takes two arguments. The first argument is the index of the list where the
desired member resides. The second argument is the index of the element itself. Here is
an example:
using System;
To access each member of the list, you can use two for loops. Use the first loop to
access each list. Nest a second loop to it to access each member. To get the dimension
of the main list, you can call the Array.GetLength() method and specify its argument
as 0. For the internal loop, pass 1 as the argument to the Array.GetLength() method.
Here is an example:
using System;
return 0;
}
}
You can also use a foreach operator to access each member of the array. When using it,
there is no need for a counter. Here is an example:
using System;
return 0;
}
}
Three-Dimensional Arrays
Instead of two dimensions, you may want to create a three-dimensional arrays. A 3-D
array is an array that, if created with the square brackets, would use two commas. Here
is an example:
using System;
return 0;
}
}
To create such an array using the Array class, you can use the following version of its
CreateInstance() method:
public static Array CreateInstance(Type elementType,
int length1,
int length2,
int length3)
Here is an example:
using System;
return 0;
}
}
To specify the value of each member of the three-dimensional array, you can call the
following version of the Array.SetValue() method:
public void SetValue (
Object value,
int index1,
int index2,
int index3
)
Here is an example:
using System;
return 0;
}
}
To get the value of each member of the three-dimensional array, you can call the
following version of the Array.GetValue() method:
public Object GetValue (
int index1,
int index2,
int index3
)
Here is an example:
using System;
return 0;
}
}
To access each member of the array, you can use three for loops. Here is an example:
using System;
return 0;
}
}
You can also use a foreach loop to access each member of the array. Here is an
example:
using System;
foreach(double n in Number)
Console.WriteLine("Number: {0}", n);
return 0;
}
}
Multidimensional Arrays
The Array class supports all dimensions of arrays beyond three. To create a
multidimensional array, the class is equipped with the following version of its
CreateInstance() method:
public static Array CreateInstance(Type elementType, params int[]
lengths)
To add elements to the list, you can use the following equivalent version of the
SetValue() method:
When you initialize an array, you add the members in an order of your choice. At one
point, when accessing the members of an array, you may want them to be arranged in
alphabetical, in numerical, or in chronological order. To assist you with re-arranging the
elements in an array, the Array class is equipped with a method named Sort that is
overloaded with as many versions as you can possibly need.
To arrange an array of the type we have used so far, you can call the following version
of the Array.Sort() method:
public static void Sort(Array array);
This is a static method that takes as argument the name of the array you want to re-
arrange. Here is an example:
using System;
Console.WriteLine("List of Numbers");
foreach(var Number in Numbers)
Console.WriteLine("Number: {0}", Number);
Array.Sort(Numbers);
Console.WriteLine("\nList of Numbers");
foreach (var Number in Numbers)
Console.WriteLine("Number: {0}", Number);
return 0;
}
}
List of Numbers
Number: 0.70257
Number: 6.48
Number: 314.905
Number: 574.9
Number: 7628.937
Number: 80458.01
Number: 293749.064
Press any key to continue . . .
Notice that the numbers are arranged in in ascending order. In the same way, if the
array is made of strings, you can call the Array.Sort() method to arrange it in
alphabetical order. If the array is made of dates, you can arrange them in chronological
order.
To arrange the members in reverse order, you can call the Array.Reverse() method.
Its syntax is:
public static void Reverse(Array array);
One of the most routine operations you can perform on an array is to find out whether it
contains this or that value. For example, if the array contains a certain member, you
may want to retrieve the index of that member. To assist you with this, the Array class
is equipped with a method named IndexOf() method that comes in various versions.
To apply it on the type of array we have used so far, you can use the following syntax:
public static int IndexOf(Array array, object value);
This method visits each member of the array, looking for the value. Once it finds value
in the array, it stops and returns the index where the first occurrence of value was
found. Here is an example of calling it:
using System;
Console.WriteLine("List of Numbers");
foreach(var Number in Numbers)
Console.WriteLine("Number: {0}", Number);
Console.WriteLine();
return 0;
}
}
If the Array.IndexOf() method finds the value in the array, it returns its position. The
above program produces:
List of Numbers
Number: 7628.937
Number: 6.48
Number: 574.9
Number: 293749.064
Number: 0.70257
Number: 314.905
Number: 80458.01
The IndexOf() method actually looks for the first occurrence of an item in an array. If
you prefer to get the last occurrence of that item in the array, you can call the
Array.LastIndexOf() method. It also is overloaded in three versions.
To better manage an array, the compiler must always be able to locate its highest and
its lowest members. This is particularly important because an array must have a size.
In both cases, the dimension argument is the rank of the array. For a single-dimensional
array, as those we have always used so far, this parameter must have the value of 0.
Introduction
To declare a variable that can hold one character, a letter, or a symbol, user the char
data type or the var keyword if you are also initializing the variable. To initialize the
variable, include its value between two single-quotes. Here are examples:
using System;
return 0;
}
}
2. To create a new class, on the main menu, click Project -> Add Class...
namespace RealEstate4
{
public enum PropertyCondition
{
Unknown,
Excellent,
Good,
NeedsRepair,
BadShape
}
public Property()
{
}
namespace RealEstate4
{
public class HouseType : Property
{
private short nbrOfStories;
private bool basement;
private bool garage;
8. To create a new class, in the Solution Explorer, right-click RealEstate4, position the
mouse on Add and click Class...
10.To create another class based on the Property class, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RealEstate4
{
public class Condominium : Property
{
private bool handicap;
11.
12.In the Solution Explorer, right- click RealEstate4 -> Add -> Class...
namespace RealEstate4
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
public PropertyListing()
{
prop = new Property();
hse = new HouseType();
cond = new Condominium();
}
try
{
Console.WriteLine("\nProperties Conditions");
Console.WriteLine("1. Excellent");
Console.WriteLine("2. Good (may need minor repair)");
Console.WriteLine("3. Needs Repair");
Console.WriteLine("4. In Bad Shape (property needs ");
Console.WriteLine("major repair or rebuild)");
Console.Write("Enter Property Condition: ");
condition = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for the " +
"condition of the property is not valid");
}
catch (Exception)
{
Console.WriteLine("An unacceptable event has just
happened");
}
if (condition == 1)
ListProperty.Condition = PropertyCondition.Excellent;
else if (condition == 2)
ListProperty.Condition = PropertyCondition.Good;
else if (condition == 3)
ListProperty.Condition = PropertyCondition.NeedsRepair;
else if (condition == 4)
ListProperty.Condition = PropertyCondition.BadShape;
else
ListProperty.Condition = PropertyCondition.Unknown;
switch ((PropertyType)propType)
{
case PropertyType.SingleFamily:
Type = PropertyType.SingleFamily;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine(
"The number of stories you entered is not allowed");
}
catch (Exception)
{
Console.WriteLine("An abnormal behavior has
occurred");
C# 3.0 Practical Learning 614
}
try
{
Console.Write(
"Does it have an indoor car garage (y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Indoor Car Garage
Answer");
}
try
{
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Basement Answer");
}
break;
case PropertyType.Townhouse:
Type = PropertyType.Townhouse;
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The number of stories " +
"you entered is not valid");
}
catch (Exception)
{
Console.WriteLine("This is one of " +
"those abnormal behaviors");
}
case PropertyType.Condominium:
Type = PropertyType.Condominium;
Console.Write("\nIs the building accessible " +
"to handicapped (y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
Condo.HandicapAccessible = true;
else
Condo.HandicapAccessible = false;
break;
default:
Type = PropertyType.Unknown;
break;
}
try
{
Console.Write("\nHow many bedrooms? ");
ListProperty.Bedrooms = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
catch (Exception)
{
Console.WriteLine("The program has decided to stop");
}
try
{
Console.Write("How many bathrooms? ");
ListProperty.Bathrooms = float.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("The computer has encountered an
error");
}
try
{
Console.Write("Year built: ");
ListProperty.YearBuilt = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have built in that
year");
}
catch (Exception)
{
try
{
Console.Write("Property Value: ");
ListProperty.Value = decimal.Parse(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("This is where the application " +
"draws the line: it stops!");
}
}
switch (Type)
{
case PropertyType.SingleFamily:
case PropertyType.Townhouse:
Type = PropertyType.SingleFamily;
Console.WriteLine("Stories: {0}",
House.Stories);
Console.WriteLine("Has Indoor Car Garage: {0}",
House.IndoorGarage);
Console.WriteLine("Finished Basement: {0}",
House.FinishedBasement);
break;
case PropertyType.Condominium:
Console.WriteLine("Handicapped Accessible Building:
{0}",
Condo.HandicapAccessible);
break;
}
Console.WriteLine("Condition: {0}",
ListProperty.Condition);
Console.WriteLine("Bedrooms: {0}",
ListProperty.Bedrooms);
Console.WriteLine("Bathrooms: {0:F}",
ListProperty.Bathrooms);
Console.WriteLine("Year Built: {0}",
ListProperty.YearBuilt);
Console.WriteLine("Market Value: {0:C}",
ListProperty.Value);
}
}
}
namespace RealEstate4
{
public class Program
{
static void Main(string[] args)
{
PropertyListing Listing = new PropertyListing();
Listing.CreateListing();
Console.WriteLine("\n");
Listing.ShowListing();
}
}
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 793742
Property Type: SingleFamily
C# 3.0 Practical Learning 618
Stories: 3
Has Indoor Car Garage: False
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 4
Bathrooms: 3.50
Year Built: 1994
Market Value: $658,225.85
return 0;
}
}
From what we have studied about arrays, if you observe a value such as "Female", you
may see that it primarily resembles a collection of characters. A string is a group of
characters. This also means that a string is an array of characters. After declaring and
initializing a string, it is considered an array of values where each character occupies a
specific position. The positioned are numbered so that the most left character of the
string occupies index 0; the second character is at index 1, and so on.
To support this idea of an array of characters, the String class is equipped with an
indexed property named Chars. This is also how you can retrieve the character at a
specific index in the string, using the [] operator of arrays. Here is an example:
using System;
Console.WriteLine();
return 0;
}
}
Once (and because) a string is considered a collection of items, you can use the foreach
operator to access each member of the collection. Here is an example:
using System;
class Exercise
{
static int Main(string[] args)
{
var gender = "Female";
Console.WriteLine("\nIndividual Characters");
foreach(char c in gender)
Console.WriteLine("Character: {0}", c);
return 0;
}
}
Individual Characters
Character: F
Character: e
Character: m
Character: a
Character: l
Character: e
Press any key to continue . . .
The English language uses two character representations: lowercase and uppercase. The
characters in lowercase are: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x,
y, and z. The equivalent characters in uppercase are represented as A, B, C, D, E, F, G,
H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, and Z. Characters used for counting
are called numeric characters; each one of them is called a digit. They are 0, 1, 2, 3, 4,
An alphabetic character, for any reason judged necessary, can be converted from one
case to another. The other characters, non-alphabetic symbols, and the numbers, do not
have a case and therefore cannot be converted in cases.
To convert a string from lowercase to uppercase, you can call use the ToUpper()
method of the String class. It is overloaded with two versions. One of the versions of
this method uses the following syntax:
public string ToUpper();
This method takes no argument. This method considers each character of the string that
called it. If the character is already in uppercase, it would not change. If the character is
a lowercase alphabetic character, it would be converted to uppercase. If the character is
not an alphabetic character, it would be kept “as-is”. Here is an example:
using System;
return 0;
}
}
To convert a string to lowercase, you can call the String.ToLower() method. Its
syntax is:
public string ToLower();
This method follows the same logic as its counterpart: it scans the string that called it,
visiting each character. If the character is not an alphabetic character, it would be kept
“as-is”. If the character is an uppercase alphabetic character, it would be converted to
lowercase. If it is in lowercase, it would not be converted.
Replacing a Character
The first argument of this method is used to identify the sought character. If and
everywhere that character is found in the string, it would be replaced by the character
passed as the second argument. Here is an example that received a telephone number
from the user and it stripped that phone number with various things to end up with only
the digits:
using System;
In many operations, you will need to know the number of characters a string consists of.
To get the size of a string, The String class provides the Length member variable.
Here is an example of using it:
using System;
return 0;
}
}
In the same way, you can access the Length property when processing the individual
characters of a string. Here is an example:
using System;
Console.WriteLine("\nIndividual Characters");
for (int c = 0; c < gender.Length; c++)
Console.WriteLine("Index[{0}]: {1}", c, gender[c]);
return 0;
}
}
Individual Characters
Index[0]: F
Index[1]: e
Index[2]: m
C# 3.0 Practical Learning 623
Index[3]: a
Index[4]: l
Index[5]: e
Press any key to continue . . .
1. To create a new file, on the main menu, click Project -> Add New Item...
namespace RealEstate4
C# 3.0 Practical Learning 624
{
public enum PropertyType
{
Unknown,
SingleFamily,
Townhouse,
Condominium
}
try
{
Console.Write("How many bathrooms? ");
string strBathrooms = Console.ReadLine();
for (int c = 0; c < strBathrooms.Length; c++)
{
if ((strBathrooms[c] != '0') &&
(strBathrooms[c] != '1') &&
(strBathrooms[c] != '2') &&
(strBathrooms[c] != '3') &&
(strBathrooms[c] != '4') &&
(strBathrooms[c] != '5') &&
(strBathrooms[c] != '6') &&
(strBathrooms[c] != '7') &&
(strBathrooms[c] != '8') &&
(strBathrooms[c] != '9') &&
(strBathrooms[c] != '.'))
throw new FloatingPointException();
}
ListProperty.Bathrooms = float.Parse(strBathrooms);
}
catch (FloatingPointException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception)
{
Console.WriteLine("The computer has encountered an
error");
}
try
{
Console.Write("Year built: ");
ListProperty.YearBuilt = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"been built in that year");
}
catch (Exception)
{
C# 3.0 Practical Learning 625
Console.WriteLine("The application is " +
"experiencing a problem");
}
try
{
Console.Write("Property Value: ");
string strValue = Console.ReadLine();
for (int c = 0; c < strValue.Length; c++)
{
if ((strValue[c] != '0') &&
(strValue[c] != '1') &&
(strValue[c] != '2') &&
(strValue[c] != '3') &&
(strValue[c] != '4') &&
(strValue[c] != '5') &&
(strValue[c] != '6') &&
(strValue[c] != '7') &&
(strValue[c] != '8') &&
(strValue[c] != '9') &&
(strValue[c] != '.'))
throw new FloatingPointException();
}
ListProperty.Value = decimal.Parse(strValue);
}
catch (FloatingPointException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception)
{
Console.WriteLine("This is where the application " +
"draws the line: it stops!");
}
}
. . . No Change
}
}
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs
C# 3.0 Practical Learning 626
major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 284866
Property Type: SingleFamily
Stories: 3
Has Indoor Car Garage: False
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 4
Bathrooms: 3.50
Year Built: 1995
Market Value: $735,000.00
Press any key to continue . . .
Types of Properties
1. Single Family
2. Townhouse
3. Condominium
4. Don't Know
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs
major repair or rebuild)
Enter Property Condition: 3
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 284866
Property Type: SingleFamily
Stories: 3
Has Indoor Car Garage: False
Finished Basement: True
Condition: NeedsRepair
Bedrooms: 4
Bathrooms: 0.00
Year Built: 1995
Market Value: $0.00
Press any key to continue . . .
Replacing a Sub-String
Inside of a string, if you have a combination of consecutive character you don't want to
keep, you can either remove that sub-string or replace it with an new combination of
consecutive characters of your choice. To support this operation, the String class
provides anopther version of the the Replace() method whose syntax is:
public string Replace(string oldStr, string newStr);
The oldStr argument is the sub-string to look for in the string. Whenever that sub-string
is found in the string, it is replaced by the newStr argument.
Formatting a String
This method takes two arguments and it follows the same techniques we reviewed in
Lesson 5 for data formatting. This means that the first argument can contain one or a
combination of {} operators that include incrementing numbers. The second argument
contains one or a combination of values that would be added to the {} operators of the
first argument.
Here is an example:
using System;
Console.WriteLine(strDisplay);
return 0;
}
}
Copying a String
After declaring and initializing one String variable, you can assign it to another String
variable using the assignment operator. Here is an example:
using System;
return 0;
}
}
Assigning one variable to another is referred to as copying it. To formally support this
operator, the String class is equipped with the Copy() method. Its syntax is:
public static string Copy(string str);
This method takes as argument an existing String object and copies it, producing a
new string. Here is an example:
using System;
class Program
{
return 0;
}
}
The string.Copy() method is used to copy all characters of one string into another
another. If you want to copy only a few characters, use the string.CopyTo() method.
Its syntax is:
public void CopyTo(int sourceIndex,
char[] destination,
int destinationIndex,
int count);
Operations on Strings
String Concatenation
One of the routine operations you can perform on two strings consists of adding one to
another, that is, putting one string to the right of another string, to produce a new string
made of both. There are two techniques you can use.
To add one string to another, you can use the addition operator as done in arithmetic.
Here is an example:
using System;
Console.WriteLine(strAddition);
return 0;
}
}
return 0;
}
}
Besides the addition operator, to formally support string concatenation, the String class
provides the Concat() method that is overloaded in various versions. One of the
versions of this method takes two String arguments. Its syntax is:
public static string Concat(string str1, string str2);
This versions takes two strings that should be concatenated. The method returns a new
string as the first added to the second. Two imitations of this version use the following
versions:
public static string Concat(string str0,
string str1,
string str2);
public static string Concat(string str0,
string str1,
string str2,
string str3);
In each case, the method takes the number of strings and adds them.
Strings Comparisons
Introduction
C# 3.0 Practical Learning 631
String comparison consists of examining the characters of two strings with a character of
one string compared to a character of the other string with both characters at the same
positions. To support this operation, the String class is equipped with the Compare()
method that is overloaded in many versions. One of the versions uses the following
syntax:
public static int Compare(string String1, string String2);
This method is declared static and it takes two arguments. When it starts, the first
character of the first argument is compared to the first character of the second string.
Alphabetically, if the first character of the first string has a lower alphabetical index than
the first character of the second, this method returns a negative value. If the first
character of the first string has a higher alphabetical index than the first character of the
second, this method returns a positive value. If the first characters of both strings are
the same, the method continues with the second character of each string. If both strings
have the exact same characters, the method returns 0. This can be resumed as follows.
The method returns
Here is an example:
using System;
return 0;
}
}
When using this version of the string.Compare() method, the case (upper or lower) of
each character is considered. If you don't want to consider this factor, the String class
proposes another version of the method. Its syntax is:
public static int Compare(string String1, string String2, bool
ignoreCase);
The third argument allows you to ignore the case of the characters when performing the
comparison.
String Equality
In the previous section, we saw that the indexed-equivalent characters of two strings
can be compared to know whether one is lower or higher than the other's. If you are
only interested to know whether two strings are equivalent, you can call the Equals()
method of the String class. It is overloaded with various versions. Two versions use the
following syntaxes:
public override bool Equals(object obj);
public bool Equals(string value);
When calling one of these versions, use an Object object or a String variable that calls
it. The method takes one argument. The variable that calls the method is compared to
the value passed as argument. If both values are the exact same, the method returns
true. The comparison is performed considering the case of each character. If you don't
want to consider the case, use the following version of the method:
public bool Equals(string value, StringComparison comparisonType);
An alternative to the second syntax is to use a static version of this method whose
syntax is:
public static bool Equals(string a, string b);
This method takes two String arguments and compares them. If they are the same,
the method returns true. This method considers the cases of the characters. If you don't
want this factor taken into consideration, use the following version of the method:
public static bool Equals(string a, string b, StringComparison
comparisonType);
Introduction
A sub-string is a section or part of a string. To create a sub-string, you first need a string
and can retrieve one or more values from it. To support this, the String class is
The integer argument specifies the position of the first character from the variable that
called the method. The return value is a new String that is made of the characters from
startIndex to the end of the string.
Sub-String Creation
Probably the most consistent way to create a string is to control the beginning and end
retrieved from the original string. To support this, the String class is equipped with
another version of the Substring() method. Its syntax is:
public string Substring(int startIndex, int length);
The first argument specifies the index of the character to start from the String variable
that calls this method. The second argument specifies the length of the string.
Introduction
In the previous sections, we learned how to create an array, how to assign values to its
elements, and how to get the value of each element. Here is an example:
using System;
Numbers[0] = 927.93;
Numbers[1] = 45.155;
Numbers[2] = 2.37094;
Numbers[3] = 73475.25;
Numbers[4] = 186.72;
Console.WriteLine();
return 0;
}
}
In the same way, if we declared an array as a member variable of a class, to access the
elements of that member, we had to use an instance of the class, followed by the period
operator, followed by the member variable applied with the square brackets. Instead of
accessing each element through its member variable, you can create a type of property
referred to as an indexer.
2. To create a new class, on the main menu, click Project -> Add Class...
namespace PropertyRental1
{
public enum Condition
{
Excellent,
Good,
NeedsRepair,
Unknown
}
public Property()
{
Random rnd = new Random();
propCode = rnd.Next(100000, 999999);
cond = Condition.Unknown;
beds = 0;
baths = 0.0f;
val = 0.00M;
}
}
}
5. To create a new class, on the main menu, click Project -> Add Class...
namespace PropertyRental1
{
public class PropertyListing
{
public Property[] props;
public PropertyListing()
{
Random rnd = new Random();
props = new Property[40];
namespace PropertyRental1
{
public class Program
{
static void Main(string[] args)
{
var properties = new PropertyListing();
var prop = new Property();
Console.WriteLine("{0}.----------------------------------",
i + 1);
Console.WriteLine("Property #: {0}",
properties .props[i].PropertyCode);
Console.WriteLine("Condition: {0}",
properties .props[i].PropertyCondition);
C# 3.0 Practical Learning 638
Console.WriteLine("Bedrooms: {0}",
properties .props[i].Bedrooms);
Console.WriteLine("Bathrooms: {0}",
properties .props[i].Bathrooms);
Console.WriteLine("Market Value: {0}\n",
properties .props[i].MonthlyRent.ToString("C"));
}
Console.WriteLine("======================================");
}
}
}
2.----------------------------------
Property #: 587917
Condition: Excellent
Bedrooms: 3
Bathrooms: 2.5
Market Value: $1,750.00
3.----------------------------------
Property #: 904376
Condition: Good
Bedrooms: 4
Bathrooms: 2.5
Market Value: $2,450.00
4.----------------------------------
Property #: 421662
Condition: Excellent
Bedrooms: 1
Bathrooms: 1
Market Value: $880.00
5.----------------------------------
Property #: 305196
Condition: Excellent
Bedrooms: 3
Bathrooms: 2.5
Market Value: $1,880.00
6.----------------------------------
Property #: 503836
Condition: Good
Bedrooms: 2
Bathrooms: 1
Market Value: $1,050.00
======================================
Press any key to continue . . .
An Indexer
An indexer, also called an indexed property, is a class's property that allows you to
access a member variable of a class using the features of an array. To create an indexed
property, start the class like any other. In the body of the class, create a field that is an
array. Here is an example:
public class Number
{
double[] Numbers = new double[5];
}
Then, in the body of the class, create a property named this with its accessor(s). The
this property must be the same type as the field it will refer to. The property must take
a parameter as an array. This means that it must have square brackets. Inside of the
brackets, include the parameter you will use as index to access the members of the
array.
Traditionally, and as we have seen so far, you usually access the members of an array
using an integer-based index. Therefore, you can use an int type as the index of the
array. Of course, the index' parameter must have a name, such as i. This would be
done as follows:
public class Number
{
double[] Numbers = new double[5];
If you want the property to be read-only, include only a get accessor. In the get
accessor, you should return an element of the array field the property refers to, using
the parameter of the property. This would be done as follows:
public class Number
{
double[] Numbers = new double[5];
Once you have created the indexed property, the class can be used. To start, you can
declare a variable of the class. To access its arrayed field, you can apply the square
brackets directly to it. Here is an example:
using System;
public Number()
{
Numbers = new double[5];
Numbers[0] = 927.93;
Numbers[1] = 45.155;
Numbers[2] = 2.37094;
Numbers[3] = 73475.25;
Numbers[4] = 186.72;
}
}
Console.WriteLine();
return 0;
}
}
Based on this, a type of formula to create and use a basic indexed property is:
class ClassName
{
DataType[] ArrayName = new DataType[Length];
public Philosopher()
{
phil[0] = "Aristotle";
phil[1] = "Emmanuel Kant";
phil[2] = "Tom Huffman";
phil[3] = "Judith Jarvis Thompson";
phil[4] = "Thomas Hobbes";
phil[5] = "Cornell West";
phil[6] = "Jane English";
phil[7] = "James Rachels";
}
}
Console.WriteLine();
return 0;
}
}
In the same way, you can created a Boolean-based indexed property by simply making
it return a bool type. Here is an example:
using System;
public DrivingWhileIntoxicated()
C# 3.0 Practical Learning 642
{
dwi[0] = false;
dwi[1] = true;
dwi[2] = true;
dwi[3] = false;
dwi[5] = false;
dwi[6] = false;
}
}
Console.WriteLine("Police Report");
Console.WriteLine("-------------------------------");
for(int i = 0; i < 7; i++)
Console.WriteLine("Driver Was Intoxicated: {0}", driving[i]);
Console.WriteLine();
return 0;
}
}
In previous lessons, we saw how to create different arrays that are numeric or string
based. Here is an example of a float array:
using System;
ages[0] = 14.50f;
ages[1] = 12.00f;
ages[2] = 16.50f;
ages[3] = 14.00f;
ages[4] = 15.50f;
Console.WriteLine();
return 0;
}
}
When using an indexed property, you can use almost any type of index, such as a real
value or a string. To do this, in the square brackets of the this property, pass the
desired type as the index. Here is an example:
public class StudentAge
{
public float this[string name]
{
}
}
When defining the indexed property, there are two rules you must follow and you are
aware of them already because an indexed property is like a method that takes a
parameter and doesn't return void. Therefore, when implementing an indexed property,
make sure you return the right type of value and make sure you pass the appropriate
index to the return value of the this property. Here is an example:
public class StudentAge
{
public float this[string name]
{
get
{
if( name == "Ernestine Jonas" )
return 14.50f;
else if( name == "Paul Bertrand Yamaguchi" )
return 12.50f;
else if( name == "Helene Jonas" )
return 16.00f;
else if( name == "Chrissie Hanson" )
return 14.00f;
else if( name == "Bernard Hallo" )
return 15.50f;
else
return 12.00f;
}
}
}
Once you have defined the property, you can use it. To access any of its elements, you
must pass the appropriate type of index. In this case, the index must be passed as a
string and not an integer. You can then do whatever you want with the value produced
by the property. For example, you can display it to the user. Here is an example:
using System;
Console.WriteLine();
return 0;
}
}
You can also pass an enumeration as an index. To do this, after defining the
enumerator, type its name and a parameter name in the square brackets of the this
member, then define the property as you see fit. To access the property outside, apply
an enumeration member to the square brackets on an instance of the class. Here is an
example:
using System;
public GolfClubMembership()
{
fee[0] = 150.95d;
fee[1] = 250.75d;
fee[2] = 85.65d;
fee[3] = 350.00d;
}
Console.WriteLine();
return 0;
}
}
namespace PropertyRental1
{
public class PropertyListing
C# 3.0 Practical Learning 646
{
public Property[] props;
public PropertyListing()
{
. . . No Change
}
}
}
namespace PropertyRental1
{
public class Program
{
static void Main(string[] args)
{
var properties = new PropertyListing();
var lngCode = 0L;
try
{
Console.Write("Enter Property Code: ");
lngCode = long.Parse(Console.ReadLine());
Console.WriteLine("======================================");
Console.WriteLine("Property Information");
Console.WriteLine("--------------------------------------");
Console.WriteLine(properties[lngCode]);
C# 3.0 Practical Learning 647
Console.WriteLine("======================================");
}
catch (FormatException)
{
Console.WriteLine("=- Invalid Property Code -=");
}
}
}
}
The indexed properties we have used so far were taking only one parameter. You can
create an indexed property whose array uses more than one dimension. To start an
indexed property that would use various parameters, first declare the array as we saw in
Lesson 24. After declaring the array, create a this property that takes the parameters.
Here is an example for an indexed property that relates to a two-dimensional array:
public class Numbers
{
double[,] nbr;
After creating the property, you can access each element of the array by applying the
square brackets to an instance of the class. Here is an example:
using System;
public Numbers()
{
nbr = new double[2,4];
nbr[0, 0] = 927.93;
nbr[0, 1] = 45.155;
nbr[0, 2] = 2.37094;
nbr[0, 3] = 73475.25;
nbr[1, 0] = 186.72;
nbr[1, 1] = 82.350;
nbr[1, 2] = 712734.95;
nbr[1, 3] = 3249.0057;
}
}
Console.WriteLine();
return 0;
Remember that one of the most valuable features of an indexed property is that, when
creating it, you can make it return any primitive type and you can make it take any
parameter of your choice. Also, the parameters of a multi-parameter indexed property
don't have to be the same type. One can be a character while the other is a bool type;
one can be a double while the other is a short, one can be an integer while the other
is a string. When defining the property, you must apply the rules of both the methods
and the arrays. Here is an example of a property that takes an integer and a string:
using System;
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
names = new string[5];
Console.WriteLine();
return 0;
}
}
In the above example, we first declared the variables to be passed as parameters to the
indexed property. You can also pass the parameter(s) directly on the instance of the
class. Here is an example:
public class Exercise
{
static int Main(string[] args)
{
var cat = new Catalog();
Console.WriteLine("Item #: 220685");
Console.WriteLine("Description: Women Floral Silk Tank Blouse");
Console.WriteLine("Unit Price: {0}", price);
Console.WriteLine();
return 0;
}
}
Just as you can create a two-dimensional indexed property, you can also create a
property that takes more than two parameters. Once again, it is up to you to decide
what type of parameter would be positioned where in the square brackets. Here is an
example of an indexed property that takes three parameters:
using System;
Console.WriteLine("Item Description");
Console.WriteLine(cat[220685, "Women Floral Silk Tank Blouse",
50.00]);
Console.WriteLine();
return 0;
}
}
To overload the this property, if two indexed properties take only one parameter, each
must take a different (data) type of parameter than the other. Here is an example:
using System;
return 0;
}
}
public StudentIdentifications()
{
studentIDs = new int[6];
studentIDs[0] = 39472;
studentIDs[1] = 13957;
studentIDs[2] = 73957;
studentIDs[3] = 97003;
studentIDs[4] = 28947;
studentIDs[5] = 97395;
Console.WriteLine("Student Identification");
Console.WriteLine("Student ID: 39472");
Console.WriteLine("Full Name: {0}\n", std[39472]);
Console.WriteLine("Student Identification");
Console.WriteLine("Full Name: Joan Ursula Hancock");
Console.WriteLine("Student ID: {0}\n", std["Joan Ursula
Hancock"]);
return 0;
}
}
Student Identification
Full Name: Joan Ursula Hancock
Student ID: 28947
C# 3.0 Practical Learning 653
Press any key to continue . . .
An indexer combines the features of an array and those of a method that takes one or
more parameters. As an array, an indexer can use one or more dimensions as we have
seen so far. Borrowing the features of a method, an indexer can take one or more
parameters and it can return a value. Besides passing different types of parameters to
various indexers, you can create some of them that take more than one parameter.
Here is an example:
using System;
return 0.00;
}
}
public Catalog()
{
nbrs = new long[5];
nbrs[0] = 273974;
nbrs[1] = 539759;
nbrs[2] = 710234;
nbrs[3] = 220685;
nbrs[4] = 192837;
Console.WriteLine("Item Identification");
Console.WriteLine("Item #: 539759");
Console.WriteLine("Unit Price: {0}\n", cat[539759]);
Console.WriteLine("Item Identification");
Console.WriteLine("Item #: 192837");
Console.WriteLine("Description: Girls Jeans with Heart Belt");
Console.WriteLine("Unit Price: {0}\n",
cat["Girls Jeans with Heart Belt", 192837]);
return 0;
}
}
Item Identification
Item #: 192837
Description: Girls Jeans with Heart Belt
Unit Price: 25.55
Introduction
So far, we have purposely used indexed properties that only produced a value. This type
is used when you are (always) in charge of specifying the values of the elements of the
array: the only action you would expect from the user is to retrieve the value of the
property. This is referred to as a read-only property. In some cases, you will use a
If you want an indexed property to be read/write, besides the get accessor as we have
been using it so far, you should also include a set accessor.
To create a read/write indexed property, you should include a set accessor for the
property. In the set accessor, assign the value contextual keyword to the field indexed
with the this parameter. Here is an example of a read/write indexed property that
includes a set accessor:
public class Number
{
double[] Numbers;
After creating the read/write property, you can assign its values outside of the class. In
other words, clients of the class can change the values to its elements. Remember that
the advantage of an indexed property is that each element of the arrayed field can be
accessed from the instance of the class by directly applying the square brackets and the
(appropriate) index to it. Here is an example:
using System;
nbr[2] = 2.37094;
Console.WriteLine();
return 0;
C# 3.0 Practical Learning 656
}
}
Based on this, a type of formula to create and use a basic indexed property is:
class ClassName
{
DataType[] ArrayName = new DataType[Index];
class Program
{
static int Main(string[] args)
{
ClassName Variable = new ClassName();
Variable[Low-Index] = Value1;
. . .
Variable[High-Index] = Value_n;
return 0;
}
}
We saw that the index of a property could be a value other than an integer-based. For
example, we created an index that was a string type. For such a property, if you make it
read/write, you can assign its values outside of the class. Here is an example of a
read/write string-based indexed property:
using System;
Console.WriteLine();
return 0;
}
}
The same rules would apply to a read/write indexed property that can receive Boolean
or decimal values.
Introduction
In the previous lesson, we learned to create and use indexer that were taking
parameters of primitive types. Just as we did with primitive types, you can create an
indexer that is of a class type. For example, you can create a class so that one of the its
fields declared as an array can be accessed with an index directly applied to an instance
of the class.
2. To create a new class, on the main menu, click Project -> Add Class...
namespace PropertyRental2
{
public enum Condition
{
Excellent,
Good,
NeedsRepair,
Unknown
}
public Property()
{
Random rnd = new Random();
propCode = rnd.Next(100000, 999999);
cond = Condition.Unknown;
beds = 0;
baths = 0.0f;
C# 3.0 Practical Learning 660
val = 0.00M;
}
5. To create a new class, on the main menu, click Project -> Add Class...
namespace PropertyRental2
{
public class PropertyListing
{
public Property[] props;
public PropertyListing()
{
Random rnd = new Random();
props = new Property[40];
namespace PropertyRental2
{
public class Program
{
static void Main(string[] args)
C# 3.0 Practical Learning 662
{
PropertyListing properties = new PropertyListing();
long lngCode;
try
{
Console.Write("Enter Property Code: ");
lngCode = long.Parse(Console.ReadLine());
Console.WriteLine("======================================");
Console.WriteLine("Property Information");
Console.WriteLine("--------------------------------------");
Console.WriteLine(properties[lngCode]);
Console.WriteLine("======================================");
}
catch (FormatException)
{
Console.WriteLine("=- Invalid Property Code -=");
}
}
}
}
When creating the class that will host the indexed property, declare an array field for the
class. Then, create the this property with the desired accessor(s). Here is an example:
public class Student
{
public string FirstName;
public string LastName;
public int Gender;
}
After creating the indexing class, you can use it and access the indexer; for example,
you can retrieve its value(s). Here is an example:
using System;
public SchoolRegistration()
{
std[0] = new Student();
std[0].FirstName = "Alfredo";
std[0].LastName = "Olmos";
std[0].Gender = 2;
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine("First Name: {0}", pupil.FirstName);
Console.WriteLine("Last Name: {0}", pupil.LastName);
Console.WriteLine("Gender: {0}\n",
(pupil.Gender == 1 ? "Female" :
(pupil.Gender == 2 ? "Male" : "Unknown")));
}
return 0;
}
}
Student Information
---------------------
First Name: Patricia
Last Name: Katts
Gender: Female
Student Information
---------------------
C# 3.0 Practical Learning 665
First Name: Josiane
Last Name: Euler
Gender: Female
Student Information
---------------------
First Name: Joan
Last Name: Jones
Gender: Unknown
Student Information
---------------------
First Name: George
Last Name: Paulson
Gender: Male
1. To create an indexer that takes an integer and returns an object, access the
PropertyListing.cs file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PropertyRental1
{
public class PropertyListing
{
public Property[] props;
public PropertyListing()
{
. . . No Change
}
}
}
namespace PropertyRental2
{
public class Program
{
C# 3.0 Practical Learning 666
static void Main(string[] args)
{
PropertyListing properties = new PropertyListing();
Console.WriteLine("Property Information");
Console.WriteLine("--------------------------------------");
Console.WriteLine("Property #: {0}",
prop.PropertyCode);
Console.WriteLine("Condition: {0}",
prop.PropertyCondition);
Console.WriteLine("Bedrooms: {0}", prop.Bedrooms);
Console.WriteLine("Bathrooms: {0}", prop.Bathrooms);
Console.WriteLine("Monthly Rent: {0}",
prop.MonthlyRent.ToString("C"));
Console.WriteLine("======================================");
}
}
}
}
Previously, we saw that you could create an indexer that takes a type than an integer.
For example, we saw that a string could be used as an index.
By now, we know that a basic indexed property produces (or all the indexed properties
we have studied so far produce) only one value. If you have a class that has only one
field, this would be enough. In reality, most of the time, a class has many fields. In such
a case, when you create an indexer , you need to be able to refer to one exact element
of the array. To make this possible, you must define a way to point to the particular
element you want. One way you can do this is to use one field of the class as a
reference. This is better if that field holds unique values among the other elements of
the array. For our Student class, we could use the StudentID field (because we will
make sure that each student has a unique ID). You can start the property as follows:
public class SchoolRegistration
{
Student[] std = new Student[5];
When a user uses this property, he or she must provide a value that uniquely identifies
an element of the array. You in turn, when you get this value, you can search for it in
the array. If you find it and the array has a get accessor, you can then return the
desired but appropriate value. Here is how this can be done:
public class SchoolRegistration
{
Student[] students = new Student[50];
After creating the indexer, you can use it. Once again, you must follow the rules of a
method that takes an argument and returns a value other than void. In this case, the
indexer must take a string and it must return a Student object. Here is an example:
using System;
public SchoolRegistration()
{
students[0] = new Student();
students[0].StudentID = 917294;
students[0].FirstName = "Helene";
students[0].LastName = "Mukoko";
students[0].Gender = Classification.Female;
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine("First Name: {0}", pupil.FirstName);
Console.WriteLine("Last Name: {0}", pupil.LastName);
Console.WriteLine("Gender: {0}\n", pupil.Gender);
pupil = pupils[192046];
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine("First Name: {0}", pupil.FirstName);
Console.WriteLine("Last Name: {0}", pupil.LastName);
Console.WriteLine("Gender: {0}\n", pupil.Gender);
return 0;
}
}
Student Information
---------------------
First Name: Armand
C# 3.0 Practical Learning 670
Last Name: Essono
Gender: Male
A Class as Index
As opposed to returning a class, an indexer can use a class as its index. When creating
such a property, the primary action you must take is to include a class and its name as a
parameter to the this property. You can start such a class as follows:
using System;
When implementing the class, you should proceed the same way we have done so far
following the rules of a method that takes an argument and returns a value other than
void. Here is an example:
After creating the property, you can use it. To do this, you must pass an object that is
the type of the index. You can then use the returned value as you see fit. Here is an
example:
using System;
public SchoolRegistration()
{
students[0] = new Student();
students[0].StudentID = 917294;
students[0].FirstName = "Helene";
students[0].LastName = "Mukoko";
C# 3.0 Practical Learning 672
students[0].Gender = Classification.Female;
Console.WriteLine("=====================");
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine(strStudent);
Console.WriteLine("=====================\n");
return 0;
}
}
You can also directly pass an instance of the class in the square brackets of the object
that holds the indexed property, as long as you specify the object. Here is an example:
using System;
public Student()
{
}
public SchoolRegistration()
{
. . . No Change
}
}
Console.WriteLine("=====================");
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine(strStudent);
Console.WriteLine("=====================\n");
return 0;
}
}
As mentioned for indexers that return primitive types, you can overload an indexed
property that produces a class. You do this following the same rules applied to method
overloading and arrays:
If two indexed properties take only one parameter, each must take a different type
of parameter than the other. The parameter can be a primitive type or a class. Here
public StudentRegistration()
{
std[0] = new Student();
std[0].StudentNumber = 304850;
std[0].FullName = "Helene Mukoko";
std[0].Gender = Classification.Female;
Console.WriteLine("--------------------------------------------------");
Console.WriteLine("--------------------------------------------------");
Console.WriteLine();
return 0;
}
}
If one property takes only one parameter, the other(s) can take more than one
parameter. An indexed property can take different parameters of primitive types as
seen in the previous lesson. An indexer can also take two or more classes as
parameters. An indexed property can also take a mix of primitive and class types as
parameters.
Here are examples:
using System;
public Student()
{
public Course()
{
}
// Unknown course
return null;
}
}
public SchoolRegistration()
{
students[0] = new Student();
students[0].StudentID = 917294;
students[0].FirstName = "Helene";
students[0].LastName = "Mukoko";
students[0].Gender = Classification.Female;
Console.WriteLine("================================================");
Console.WriteLine("Student Registration");
Console.WriteLine("------------------------------------------");
Console.WriteLine(pupils[crs, std]);
Console.WriteLine("================================================");
Console.WriteLine("Student Registration");
Console.WriteLine("------------------------------------------");
Console.WriteLine(pupils[std, crs, true]);
Console.WriteLine("================================================\n");
return 0;
}
}
1. To overload the indexer, access the PropertyListing.cs file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PropertyRental1
{
public class PropertyListing
{
public Property[] props;
public PropertyListing()
{
. . . No Change
}
}
}
namespace PropertyRental2
{
public class Program
{
static void Main(string[] args)
{
PropertyListing properties = new PropertyListing();
C# 3.0 Practical Learning 684
long lngCode;
try
{
Console.Write("Enter Property Code: ");
lngCode = long.Parse(Console.ReadLine());
Console.WriteLine("======================================");
Console.WriteLine("Property Information");
Console.WriteLine("--------------------------------------");
Console.WriteLine(properties[lngCode]);
Console.WriteLine("======================================");
}
catch (FormatException)
{
Console.WriteLine("=- Invalid Property Code -=");
}
}
}
}
As done for a primitive type, you can allow the clients of your indexer to assign values to
the array's elements. Once again, when defining the property, you should include a set
accessor to it. In the set accessor, you should assign the value keyword to an element
of the array. Here is an example:
public class SchoolRegistration
{
Student[] std = new Student[5];
After doing this, you can create an element of the array by applying the square brackets
to the instance of the class and assigning the desired value to it. The problem with the
class is that, since it may have many fields (or properties), to completely define each
element, you must provide a value to the member variables of the class itself. Here is an
example:
C# 3.0 Practical Learning 685
using System;
Console.WriteLine("Student Information");
Console.WriteLine("---------------------");
Console.WriteLine("First Name: {0}", registration[2].FirstName);
Console.WriteLine("Last Name: {0}", registration[2].LastName);
Console.WriteLine("Gender: {0}\n",registration[2].Gender);
return 0;
}
}
Array-Based Lists
Introduction
A collection, also called a list, is many items of the same kind grouped into one entity.
The collection can be based on simple numbers, basic symbols, dates, strings, times.
The collection can also be made of objects that each is made of internal values. This
means that a collection can be made of such objects as houses, people, cars, countries,
electronic devices. The primary rule to observe is that all items included in a list must be
described using the same characteristics. Based on this, if the collection is made of cars,
it should contain only cars, not cars and countries.
There are various types of lists or collections. An array-based list is one whose number
of items is known in advance. For example, an array-based collection of 10 cars contains
10 cars, may-be less but not more (in reality, the Array class of the .NET Frameword
provides a method used to expand an array).
Setting Up a Collection
To use a collection as an entity, you can create a class for it. This class would be used to
add items in the collection, to remove items in the list, or to perform other necessary
operations. You can start a simple class as follows:
class Collection
{
public Collection()
{
}
}
After creating the class for a collection, the collection becomes an object and its class
can be used like any other. This means that, before using the collection, you can declare
a variable for it. Here is an example:
using System;
class Collection
{
public Collection()
{
}
}
return 0;
}
}
For an array-based list, because you must specify the number of items that the list will
contain, you can declare an array as a field. Here is an example:
class Collection
{
// This collection will be a list of decimal numbers
private double[] Item = new double[20];
Although you can initialize an array in a C# class, remember that you can also use a
constructor to initialize it. Here is an example:
class Collection
{
public int MaxCount = 20;
A primary accessory you need when using a list is a count of the number of items in the
list when/as they are added or deleted. This accessory is primarily a private field as a
simple natural number. When the class is declared, this member variable should be set
to 0 to indicate that the list is primarily empty:
class Collection
{
public int MaxCount = 20;
Since the size field was declared private, if you plan to get the count of items in the list
from outside the class, you should (must) provide a property to take care of this. This
can simply be done as follows:
using System;
class Collection
{
public int MaxCount = 20;
Adding an Item
Creating a collection consists of adding items to it. Items are usually added one at a
time. The easiest way to do this is to add an item at the end of the existing collection.
To add an item to the collection, because an array has (or is supposed to have) a fixed
number of items, you should first check whether the list is already full. For an array-
based list, the collection is full if its count of items is equal to the maximum number of
items it can hold. If the collection can still receive at least one item, you can add the
item at the end of the list and increase the count by one. Here is how this can be done:
class Collection
{
public int MaxCount = 20;
Once you have a means of adding items to the list, you can effectively create a list of
items. Here is an example:
public class Exercise
{
static int Main(string[] args)
{
var list = new Collection();
list.Add(224.52);
list.Add(60.48);
list.Add(1250.64);
list.Add(8.86);
list.Add(1005.36);
After adding items to a collection, you can retrieve them to do what you intended the list
for. To retrieve an item, you can locate it by its position, the same way you would do for
an array. Having this index, you can check whether the position specified is negative or
higher than the current count of items. If it is, there is nothing much to do since the
index would be wrong. If the index is in the right range, you can retrieve its
corresponding item. The method to do this can be implemented as follows:
using System;
class Collection
{
public int MaxCount = 20;
list.Add(224.52);
list.Add(60.48);
list.Add(1250.64);
list.Add(8.86);
list.Add(1005.36);
return 0;
}
}
Inserting a new item in the collection allows you to add one at a position of your choice.
To insert an item in the list, you must provide the new item and the desired position.
Before performing this operation, you must check two things. First, the list must not be
empty because if it is, then there is no way to insert an item (you insert something
between two things, not something between nothing). Second, the specified position
must be in the allowed range.
class Collection
{
public int MaxCount = 20;
// Now that we have room, put the new item in the position
created
this.Item[pos] = itm;
list.Add(224.52);
list.Add(60.48);
list.Add(1250.64);
list.Add(8.86);
list.Add(1005.36);
list.Insert(-707.16, 2);
return 0;
}
}
Item 1: 224.52
Item 2: 60.48
Item 3: -707.16
Item 4: 1250.64
Item 5: 8.86
Item 6: 1005.36
Number of Items: 6
Another operation you can perform on a collection consists of deleting an item. This is
also referred to as removing the item. To delete an item from the collection, you can
class Collection
{
public int MaxCount = 20;
// Now that we have room, put the new item in the position
created
this.Item[pos] = itm;
list.Add(224.52);
list.Add(60.48);
list.Add(1250.64);
list.Add(8.86);
list.Add(1005.36);
list.Insert(-707.16, 2);
list.Insert(-369952.274, 4);
list.Delete(5);
list.Delete(3);
return 0;
}
}
Item 1: 224.52
Item 2: 60.48
Item 3: -707.16
Item 4: 1250.64
Item 5: -369952.274
Item 6: 8.86
Item 7: 1005.36
Number of Items: 7
Item 1: 224.52
Item 2: 60.48
C# 3.0 Practical Learning 699
Item 3: -707.16
Item 4: -369952.274
Item 5: 1005.36
Number of Items: 5
A Collection of Items
Introduction
We have learned how to create an array as a list of items. Like an array, a collection is a
series of items of the same type. The particularity with creating an array is that you
must know in advance the number of items that will make up the list (in reality, in
the .NET Framework, you just have to specify an initial count, such as 5; then, before
adding a new item, you can check if there is room, if there is no room, you can provide
room first, then add the new item). There are times when you don't know, you can't
know, or you can't predict the number of items of the list. For this reason, you may want
to create the list for which you don't specify the maximum number of items but you
allow the user of the list to add, locate, or remove items at will.
Before creating a list, you probably should first decide or define what the list would be
made of. As different as collections are, one list can be made of numeric values, such as
a list that will be made of numbers. You may want a list that is made of names. Such a
list can be created from a class that includes a string member variable. Another type of
list can contain complex objects.
2. To save the project, on the Standard toolbar, click the Save All button
4. To create a new class, in the Solution Explorer, right-click FlowerShop4 -> Add ->
Class...
namespace FlowerShop4
{
public enum FlowerType
{
public Flower()
{
Type = FlowerType.Mixed;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
pc = 0.00M;
}
7. To create a new class, in the Solution Explorer, right-click FlowerShop4 -> Add ->
Class...
namespace FlowerShop4
{
public class OrderProcessing
{
public Flower FlowerOrder;
private int qty;
public OrderProcessing()
{
FlowerOrder = new Flower();
}
do
{
try
{
Console.WriteLine("Enter the Type of Flower Order");
Console.WriteLine("1. Roses");
Console.WriteLine("2. Lilies");
Console.WriteLine("3. Daisies");
Console.WriteLine("4. Carnations");
Console.WriteLine("6. Mixed");
Console.Write("Your Choice: ");
C# 3.0 Practical Learning 702
choice = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You failed to enter an " +
"appropriate number!");
}
switch (choice)
{
case 1:
FlowerOrder.Type = FlowerType.Roses;
break;
case 2:
FlowerOrder.Type = FlowerType.Lilies;
break;
case 3:
FlowerOrder.Type = FlowerType.Daisies;
break;
case 4:
FlowerOrder.Type = FlowerType.Carnations;
break;
case 5:
FlowerOrder.Type = FlowerType.LivePlant;
break;
default:
FlowerOrder.Type = FlowerType.Mixed;
break;
}
}
do
{
try
{
Console.WriteLine("Enter the Color");
Console.WriteLine("1. Red");
Console.WriteLine("2. White");
Console.WriteLine("3. Yellow");
Console.WriteLine("4. Pink");
Console.WriteLine("5. Orange");
Console.WriteLine("6. Blue");
Console.WriteLine("7. Lavender");
Console.WriteLine("8. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You didn't enter an " +
"appropriate number!");
C# 3.0 Practical Learning 703
}
switch (choice)
{
case 1:
FlowerOrder.Color = FlowerColor.Red;
break;
case 2:
FlowerOrder.Color = FlowerColor.White;
break;
case 3:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 4:
FlowerOrder.Color = FlowerColor.Pink;
break;
case 5:
FlowerOrder.Color = FlowerColor.Yellow;
break;
case 6:
FlowerOrder.Color = FlowerColor.Blue;
break;
case 7:
FlowerOrder.Color = FlowerColor.Lavender;
break;
default:
FlowerOrder.Color = FlowerColor.Mixed;
break;
}
}
do
{
try
{
Console.WriteLine("Enter the Type of Arrangement");
Console.WriteLine("1. Bouquet");
Console.WriteLine("2. Vase");
Console.WriteLine("3. Basket");
Console.WriteLine("4. Mixed");
Console.Write("Your Choice: ");
choice = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("You didn't provide an " +
"acceptable number!");
}
switch (choice)
{
case 1:
FlowerOrder.Arrangement = FlowerArrangement.Bouquet;
break;
case 2:
FlowerOrder.Arrangement = FlowerArrangement.Vase;
break;
case 3:
FlowerOrder.Arrangement = FlowerArrangement.Basket;
break;
default:
FlowerOrder.Arrangement = FlowerArrangement.Any;
break;
}
}
try
{
Console.Write("Enter the Unit Price: ");
FlowerOrder.UnitPrice =
Math.Abs(decimal.Parse(Console.ReadLine()));
}
catch (FormatException)
{
Console.WriteLine("You didn't specify a valid price!");
}
try
{
Console.Write("Enter Quantity: ");
Quantity = Math.Abs(int.Parse(Console.ReadLine()));
}
catch (FormatException)
{
Console.WriteLine("The quantity you entered " +
"is not acceptable!");
}
}
namespace FlowerShop4
{
public class Program
{
static void Main(string[] args)
{
var order = new OrderProcessing();
order.ProcessOrder();
Console.WriteLine();
order.ShowOrder();
Console.WriteLine();
}
}
}
=======================
==-=-=Flower Shop=-=-==
-----------------------
Flower Type: Daisies
Flower Color: Mixed
Arrangement: Bouquet
Price: $45.50
Quantity: 3
Total Price: $136.50
=======================
Implementing a Collection
After deciding what each item of the list would be made of, you can create a class that
would manage the list. This class would be responsible for all operations that can be
performed on the list. If the list will be made of primitive values, you can directly create
a field of the desired type. Here is an example:
using System;
return 0;
}
}
If the list will be made of objects, you can first create a class that specifies those types
of items and then declare its variable in the list class. Here is an example of a simple
class that holds a double-precision value:
using System;
return 0;
}
}
When creating a list, one of the aspects you should pay attention to is to keep track of
the number of items in the list. To do this, you can create a property that holds the
number. The value of this property would increase as the items are added to the list and
the value would decrease as the items are removed from the list. Here is how this can
be done:
using System;
public Numbers()
{
size = 0;
}
return 0;
}
}
1. To create a new class, in the Class View, right-click FlowerShop4 -> Add -> Class...
namespace FlowerShop4
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
}
}
}
A good collection is a list that can grow or shrink as the user wishes. When creating the
list, you don't need to predict the maximum number of items that will be added to the
list. When a list starts, it is empty or at least it must be considered like that, before any
item is added to it. To specify this, you should declare a primary member variable.
Although you can call it anything, it is usually called Head:
public Numbers()
{
size = 0;
Head = null;
}
We saw that when using an array, each member could be accessed using its index. If
the items of a collection are not indexed, you must provide a mechanism to locate an
item. To do this, you can use a starting point that determines the beginning of the list.
Then, to locate an item, you can check whether another item follows that starting point:
If no item follows an item, either you are at the end of the list or the list is empty.
To be able to scan a list from one item to another, you can declare a field. Although this
member variable can be called anything, for the sake of clarify, you should call it Next.
The field is the same type as its class. Here is an example:
C# 3.0 Practical Learning 710
public class Number
{
public double Item;
public Number Next;
}
namespace FlowerShop4
{
. . . No Change
namespace FlowerShop4
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
Head = null;
}
}
}
3. Save all
Operations on a Collection
Adding an Item
Since a list is fundamentally empty when it starts, the primary operation you can
perform on a list is to add a new item to it. In order to indicate that you want to add an
item to the list, you can create a method that receives an item as argument. For the
return type, you have two main options. Because the main job of this method is to add a
new item, which it hardly fails to do if you implement it right, it can be defined as void.
Alternatively, you can make it return the position of the new item in the list. Here is an
example:
public class Numbers
{
int size;
Number Sample;
public Number Head;
public Numbers()
{
size = 0;
Head = null;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return size++;
}
}
namespace FlowerShop4
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
Head = null;
}
Sample = NewFlower;
Sample.Next = Head;
Head = Sample;
return items++;
}
}
}
namespace FlowerShop4
{
C# 3.0 Practical Learning 713
public class Program
{
static void Main(string[] args)
{
var flowers = new FlowerInventory();
var nice = new Flower();
nice.Type = FlowerType.Lilies;
nice.Color = FlowerColor.White;
nice.Arrangement = FlowerArrangement.Bouquet;
nice.UnitPrice = 39.95M;
flowers.Add(nice);
3. Save all
Retrieving an Item
Once a list exists, the user can explore it. One of the operations performed on a
collection is to locate and retrieve an item. To do this, you can create a method that
takes as argument an index. The method would examine the argument with regards to
the number of items in the list to make sure the argument's value is in the range of the
current items of the list. If the number is too low or too high, the method can return null
or 0. If the number is in the range, the method can return the item at that position.
Here is an example:
public Numbers()
{
size = 0;
Head = null;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return size++;
}
namespace FlowerShop4
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
Head = null;
}
Sample = NewFlower;
Sample.Next = Head;
Head = Sample;
return items++;
}
for(int i = Count - 1;
i > index && Current != null;
i--)
Current = Current.Next;
return Current;
}
}
}
namespace FlowerShop4
{
public class Program
{
static void Main(string[] args)
{
var flowers = new FlowerInventory();
var nice = new Flower();
nice.Type = FlowerType.Lilies;
nice.Color = FlowerColor.White;
C# 3.0 Practical Learning 716
nice.Arrangement = FlowerArrangement.Bouquet;
nice.UnitPrice = 39.95M;
flowers.Add(nice);
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
Console.WriteLine("Total: {0} flower items in current
inventory",
flowers.Count);
Console.WriteLine("--------------------------------------------");
Console.WriteLine("Inventory Summary");
for (int i = 0; i < flowers.Count; i++)
{
Console.WriteLine("------------------------");
Console.WriteLine("Flower Information");
Console.WriteLine("Type: {0}",
flowers.Get(i).Type);
Console.WriteLine("Color: {0}",
flowers.Get(i).Color);
Console.WriteLine("Arrangement: {0}",
flowers.Get(i).Arrangement);
Console.WriteLine("Unit Price: {0:F}",
flowers.Get(i).UnitPrice);
}
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
}
}
}
Removing an Item
Deleting an item consists of removing it from the list. There are two main approaches
you can use. You can simply ask the class to delete an item. In this case, it is usually the
item at the end that gets deleted. If you do this, make sure you perform other routine
operations such as decrementing the count of items in the list. Here is an example:
public class Numbers
{
. . . No Change
Number Current;
Current = Head.Next;
Head.Next = Current.Next;
size--;
return true;
}
}
Another technique used to delete an item consists of specifying the position of the item
to be deleted. To do this, you can pass an argument as the desired position. The
method would check the range of values of the current list. If the specified position is
beyond the appropriate range, the method can return false, 0, or null, depending on
how you create it.
namespace FlowerShop4
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
Head = null;
}
C# 3.0 Practical Learning 719
public override int Add(Flower NewFlower)
{
Flower Sample = new Flower();
Sample = NewFlower;
Sample.Next = Head;
Head = Sample;
return items++;
}
for(int i = Count - 1;
i > index && Current != null;
i--)
Current = Current.Next;
return Current;
}
Flower Current;
Current = Head.Next;
Head.Next = Current.Next;
items--;
return true;
}
}
}
namespace FlowerShop4
{
public class Program
{
static void Main(string[] args)
{
var flowers = new FlowerInventory();
var nice = new Flower();
nice.Type = FlowerType.Lilies;
nice.Color = FlowerColor.White;
nice.Arrangement = FlowerArrangement.Bouquet;
C# 3.0 Practical Learning 720
nice.UnitPrice = 39.95M;
flowers.Add(nice);
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
Console.WriteLine("Total: {0} flower items in current
inventory",
flowers.Count);
Console.WriteLine("--------------------------------------------");
Console.WriteLine("Inventory Summary");
for (var i = 0; i < flowers.Count; i++)
{
Console.WriteLine("------------------------");
Console.WriteLine("Flower Information");
Console.WriteLine("Type: {0}",
flowers.Get(i).Type);
Console.WriteLine("Color: {0}",
flowers.Get(i).Color);
Console.WriteLine("Arrangement: {0}",
flowers.Get(i).Arrangement);
Console.WriteLine("Unit Price: {0:F}",
flowers.Get(i).UnitPrice);
}
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
flowers.Delete();
flowers.Delete();
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
C# 3.0 Practical Learning 721
Console.WriteLine("Total: {0} flower items in current
inventory",
flowers.Count);
Console.WriteLine("--------------------------------------------");
Console.WriteLine("Inventory Summary");
for (var i = 0; i < flowers.Count; i++)
{
Console.WriteLine("------------------------");
Console.WriteLine("Flower Information");
Console.WriteLine("Type: {0}",
flowers.Get(i).Type);
Console.WriteLine("Color: {0}",
flowers.Get(i).Color);
Console.WriteLine("Arrangement: {0}",
flowers.Get(i).Arrangement);
Console.WriteLine("Unit Price: {0:F}",
flowers.Get(i).UnitPrice);
}
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
}
}
}
Locating an Item
One of the operations hardly performed on a list is to find an item. This is because if you
ask a list to locate a particular item, you must provide as much information as possible.
Probably the most expedient way you can do this is to completely define an item and
pass it to the list. Only if the (exact) item is found in the list would it be recognized.
Here is an example:
using System;
public Numbers()
{
size = 0;
Head = null;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return size++;
}
Number Current;
Current = Head.Next;
Head.Next = Current.Next;
size--;
return true;
}
if (toFind == null)
return false;
return false;
}
}
reals.Delete();
Found = reals.Find(nbrToFind);
if (Found == true)
Console.WriteLine("The number {0} was found in the list\n",
nbrToFind.Item);
else
Console.WriteLine("The number {0} was NOT found in the
list\n",
nbrToFind.Item);
return 0;
}
}
Number of items: 5
Number[0] = 2974.03
Number[1] = 748.25
Number[2] = 50883.82
Number[3] = 29.24
Number[4] = 106628.06
Iterating Through a
Collection
When studying arrays, we saw that you could use a for loop to visit each member of an
array. This was also done with the help of the [] operator. In previous lessons, we saw
that, when creating a collection, you should provide a method that allows you to retrieve
a member of the collection. In both cases, you can list the members of an array or a
collection through a technique called an enumeration. Enumerating a collection consists
of visiting each member of the list, for any reason judged necessary. For example, you
can enumerate a collection to display a list of its members. You can enumerate a
collection when looking for a member that responds to a certain criterion.
Besides, or instead of, a for loop, the .NET Framework provides another and better
support for enumeration. In the C# language, you can enumerate a collection using the
foreach operator, but the collection must be prepared for it: you cannot just use
foreach for any collection. This support is provided through two main interfaces:
IEnumerator and IEnumerable. These two interfaces are defined in the
System.Collection namespace. Therefore, if you intend to use them, you can include
this namespace in your source file.
2. To create a new file, on the main menu, click Project -> Add New Item...
6. To create a new class, in the Solution Explorer, right-click FlowerShop5 -> Add ->
Class...
namespace FlowerShop5
{
public class Flower
{
public Flower()
{
Type = FlowerType.Mixed;
Color = FlowerColor.Mixed;
Arrangement = FlowerArrangement.Vase;
pc = 0.00M;
}
9. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
namespace FlowerShop5
{
public abstract class AFlower
{
protected int items;
public AFlower()
{
items = 0;
}
public FlowerInventory()
{
Head = null;
}
Sample.Next = Head;
Head = Sample;
return items++;
}
for(int i = Count - 1;
i > index && Current != null;
i--)
Current = Current.Next;
return Current;
}
Flower Current;
Current = Head.Next;
Head.Next = Current.Next;
items--;
return true;
}
}
}
12.Save all
The IEnumerator interface provides the means of identifying the class that holds a
sample of the items that will be enumerated. This interface is equipped with one
property and two methods. To use the functionalities provided by the IEnumerator
interface, you must create a class that implements it. You can start the class as follows:
public class Enumerator : IEnumerator
{
}
If your collection is an array-based list, you can start by declaring the base array in the
class: Here is an example:
public class Enumerator : IEnumerator
{
private double[] numbers;
}
The role of the enumerator is to act on a collection. For this reason, the class should be
prepared to receive an external collection. This can be done by passing it to a
constructor of the enumerator. Here is an example:
public class Enumerator : IEnumerator
{
private double[] numbers;
The internal collection would be used in the enumerator class. The external collection
would be the source of the values of the list that would be enumerated. For these
reasons, you can/should initialize the internal collection with the values of the external
list. This can be done as follows:
public class Enumerator : IEnumerator
{
private double[] numbers;
1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
namespace FlowerShop5
{
public class FlowerIdentifier : IEnumerator
{
public FlowerInventory counts;
In the previous lesson, when introducing some techniques of creating a list, we saw that
you should have a type of tag, as a field, that allows you to monitor the item that is
being currently accessed or used in the list. This is particularly valuable when visiting the
members of the collection. The IEnumerator interface provides a property that is used
to identify the current member of the list. This property is called Current. Because the
current item is meant to be viewed only, the Current property is a read-only member.
Based on the rules of abstract classes, remember that you must implement all members
of an interface in the class that is based on it.
To implement the Current property, you can define its get accessor to return the item
at the current position. This can be done as follows:
public class Enumerator : IEnumerator
{
private double[] numbers;
private int cur;
namespace FlowerShop5
{
public class FlowerIdentifier : IEnumerator
{
private int curPosition = -1;
public FlowerInventory counts;
Although you should be able to identify the current item at any time, when the
application starts, before the collection can be enumerated, the tag that is used to
monitor the current item should be set to a value before the beginning of the count.
This can be done by setting the tag to -1. Here is an example:
public class Enumerator : IEnumerator
{
private double[] numbers;
private int cur;
While the collection is being used, at one moment you may want to reset the tag of the
current item to its original position. To support this operation, the IEnumerator
interface is equipped with a method named Reset. Its syntax is:
void Reset();
When implementing this method, simply assign a non-existing value, which is usually -1,
to the monitoring tag of the current item. This can be done as follows:
public class Enumerator : IEnumerator
{
private double[] numbers;
private int cur;
When using the implementer of the IEnumerator interface, if you try accessing an item
beyond the maximum number of items, the compiler would throw an
IndexOutOfRangeException exception. For this reason, when anticipating a bad
behavior, you should catch this exception when implementing the Current property.
namespace FlowerShop5
{
public class FlowerIdentifier : IEnumerator
{
private int curPosition = -1;
public FlowerInventory counts;
In the previous lesson, we saw that, when using the items of a collection, one way you
could locate one item from another was to be able to jump from one item to the next.
This operation is also very important when enumerating a collection. To support this
operation, the IEnumerator interface is quipped with the MoveNext() method. Its
syntax is:
bool MoveNext();
When implementing this method, first increment the tag that monitors the current item
of the collection. After incrementing the tag, check whether it is lower than the total
number of items. If it is, return true. Otherwise, return false. This can be done as
follows:
public class Enumerator : IEnumerator
{
private double[] numbers;
private int cur;
namespace FlowerShop5
{
public class FlowerIdentifier : IEnumerator
{
private int curPosition = -1;
public FlowerInventory counts;
return null;
}
}
Introduction
While the IEnumerator interface is used to identify the class that holds each value that
will be visited, the IEnumerable interface is used to communicate with the collection
whose items will be enumerated. For this reason, when implementing this class, you
should provide the means of accessing the external collection. This can be done by
passing a collection of the class that holds the values, to a constructor of the
IEnumerable implementer.
To implement the IEnumerable interface, start by deriving a class from it. While the
class implemented by the IEnumerator interface represents an object, the class that
implements the IEnumerable interface is a collection. Here is an example:
public class Enumerable : IEnumerable
{
}
The new class does not know what collection it will be asked to enumerate. For this
reason, in the new class, you should declare a member variable of the class that holds
the values that will be enumerated. If the collection is array-based, you can create the
field as follows:
public class Enumerable : IEnumerable
{
private double[] numbers;
}
Eventually, when instantiating the IEnumerable implementer, you will need to pass it a
collection of values. To make this possible, you can create a method in the new class
and pass that collection of objects. Here is an example:
public class Enumerable : IEnumerable
{
private double[] numbers;
In this method, you can assign the member variable to the argument. You should also
assign each member of the argument to its equivalent of the member of the argument.
This can be done with a for loop as follows:
public class Enumerable : IEnumerable
To support the use of the foreach loop, the IEnumerable interface is equipped with
(only) a method named GetEnumerator that you must implement. The
IEnumerable.GetEnumerator() method returns an IEnumerator object. When
implementing this method, you can return an object of the class that implements the
IEnumerator interface, passing it the collection that was declared in the IEnumerable
implementer. This can be done as follows:
public class Enumerable : IEnumerable
{
private double[] numbers;
1. To create a new class, in the Class View, right-click FlowerShop5 -> Add -> Class...
namespace FlowerShop5
{
public class Flowers : IEnumerable
{
private FlowerInventory items;
fid.Identify(items);
return fid;
}
}
}
Using foreach
After implementing the IEnumerator and the IEnumerable interfaces, you can then
use the foreach loop. To start, you must prepare the collection and its items for
processing. Here is an example:
public class Exercise
{
static int Main(string[] args)
{
double[] numbers = new double[5];
numbers[0] = 224.52;
numbers[1] = 60.48;
numbers[2] = 1250.64;
numbers[3] = 8.86;
numbers[4] = 1005.36;
return 0;
}
}
coll.Identify(numbers);
foreach (double d in coll)
Console.WriteLine("Item {0}", d); ;
return 0;
}
}
namespace FlowerShop5
{
public class Program
{
static void Main(string[] args)
{
FlowerInventory fls = new FlowerInventory();
Flower nice;
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
Console.WriteLine("Total: {0} flower items in current
inventory",
fls.Count);
C# 3.0 Practical Learning 741
Console.WriteLine("--------------------------------------------");
Console.WriteLine("Inventory Summary");
foreach (Flower flr in collection)
{
Console.WriteLine("------------------------");
Console.WriteLine("Flower Information");
Console.WriteLine("Type: {0}", flr.Type);
Console.WriteLine("Color: {0}", flr.Color);
Console.WriteLine("Arrangement: {0}", flr.Arrangement);
Console.WriteLine("Unit Price: {0:F}", flr.UnitPrice);
}
Console.WriteLine("//=//=//=//=//=//=//=//=//=//=//=//=//=//=//");
}
}
}
To provide a common abstract techniques of creating and using lists, the .NET
Framework provides the ICollection interface. This interface is equipped with a
property to keep track of the number of items in a list: the Count property. It is also
equipped with a method to copy the items from a list to an array.
To support the creation of any kind of list, the Microsoft .NET Framework provides the
ArrayList class. The ArrayList class implements the ICollection interface. This
class can be used to add, locate, or remove an item from a list. The class provides many
other valuable operations routinely done on a list.
Because of its flexibility, ArrayList is the most used class to create lists of items of any
kind in a .NET application. Besides the ability to handle any type of list, ArrayList is
a good class to study the theory of a collection. The routine operations found in the
ArrayList class are the same found in many other collection-based classes you would
use when creating commercial or graphical applications.
Besides the ability to create a collection, the ArrayList class has the built-in
mechanism for serialization.
2. To save the project, on the Standard toolbar, click the Save All button
namespace RealEstate5
{
public enum PropertyCondition
{
Unknown,
Excellent,
Good,
NeedsRepair,
BadShape
}
[Serializable]
public class Property
{
private string propNbr;
private PropertyCondition cond;
private short beds;
private float baths;
private int yr;
private decimal val;
7. To create a new class, in the Class View, right-click RealEstate5 -> Add -> Class...
namespace RealEstate5
{
[Serializable]
public class Condominium : Property
{
private bool handicap;
public Condominium()
{
this.PropertyType = "Condominium";
}
namespace RealEstate5
{
[Serializable]
public class HouseType : Property
{
private short nbrOfStories;
private bool basement;
private bool garage;
13.To create a new class, in the Solution Explorer, right-click RealEstate5 -> Add ->
Class...
namespace RealEstate5
{
[Serializable]
public class Townhouse : HouseType
{
private bool comm;
C# 3.0 Practical Learning 747
public Townhouse()
{
this.PropertyType = "Townhouse";
}
16.To create a new class, in the Class View, right-click RealEstate5 -> Add -> Class...
namespace RealEstate5
{
[Serializable]
public class SingleFamily : HouseType
{
public SingleFamily()
{
this.PropertyType = "Single Family";
}
}
}
19.Save all
After declaring an ArrayList variable, it is empty. As objects are added to it, the list
grows. The list can grow tremendously as you wish. The number of items of the list is
managed through the memory it occupies and this memory grows as needed. The
number of items that the memory allocated is currently using is represented by the
ArrayList.Capacity property. This will usually be the least of your concerns.
If for some reason, you want to intervene and control the number of items that your
ArrayList list can contain, you can manipulate the Capacity property. For example,
you can assign it a constant to set the maximum value that the list can contain. Once
again, you will hardly have any reason to use the Capacity property: the compiler
knows what to do with it.
If you set a fixed size on an ArrayList list, you may not be able to add a new item
beyond the limit. In fact, if you attempt to do this, you may receive an error. A safe way
A Read-Only List
One of the reason for creating a list is to be able to add items to it, edit its items,
retrieve an items, or delete items from it. These are the default operations. You can still
limit these operations as you judge them unnecessary. For example, you may create a
list and then initialize it with the items that you want the list to only have. If you don't
intend to have the user adding items to it, you can create the list as read-only. To do
this, you can call the ArrayList.ReadOnly() method. It is overloaded with two
versions as follows:
public static ArrayList ReadOnly(ArrayList);
public static IList ReadOnly(IList);
This method is static. This means that you don't need to declare an instance of
ArrayList to call them. Instead, to make the list read-only, call the
ArrayList.ReadOnly() method and pass your ArrayList variable to it.
As we will see in the next sections, some operations cannot be performed on a read-only
list. To perform such operations, you can first find out whether an ArrayList list is
read-only. This is done by checking its IsReadOnly property.
Item Addition
The primary operation performed on a list is to create one. One of the biggest
advantages of using a linked list is that you don't have to specify in advance the number
of items of the list as done for an array. You can just start adding items. The ArrayList
class makes this possible with the Add() method. Its syntax is:
public virtual int Add(object value);
The argument of this method is the value to add to the list. If the method succeeds with
the addition, it returns the position where the value was added in the list. This is usually
the last position in the list. If the method fails, the compiler would throw an error. One
of the errors that could result from failure of this operation would be based on the fact
that either a new item cannot be added to the list because the list is read-only, or the
list was already full prior to adding the new item. Normally, a list can be full only if you
had specified the maximum number of items it can contain using the
ArrayList.Capacity property. As mentioned above, the list can be made read-only by
passing its variable to the ArrayList.ReadOnly() method.
1. To create an inventory, on the main menu, click Project -> Add Class...
namespace RealEstate5
{
public class PropertyManagement
{
private Condominium Condo;
private Townhouse TownHome;
private SingleFamily House;
private ArrayList Condominiums;
private ArrayList Townhouses;
private ArrayList SingleFamilies;
public PropertyManagement()
{
Condo = new Condominium();
TownHome = new Townhouse();
House = new SingleFamily();
Condominiums = new ArrayList();
Townhouses = new ArrayList();
SingleFamilies = new ArrayList();
strPropertyNumber = "000000";
try
{
// If a directory for the properties has not yet
// been created, then create them
Directory.CreateDirectory(strPropertiesDirectory);
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The directory could " +
"not be created");
}
}
try
{
Console.WriteLine("\nProperties Conditions");
Console.WriteLine("1. Excellent");
Console.WriteLine("2. Good (may need minor repair)");
Console.WriteLine("3. Needs Repair");
Console.Write("4. In Bad Shape (property needs ");
Console.WriteLine("major repair or rebuild)");
C# 3.0 Practical Learning 750
Console.Write("Enter Property Condition: ");
condition = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the condition of the property is not valid");
}
if (condition == 1)
return PropertyCondition.Excellent;
else if (condition == 2)
return PropertyCondition.Good;
else if (condition == 3)
return PropertyCondition.NeedsRepair;
else if (condition == 4)
return PropertyCondition.BadShape;
else
return PropertyCondition.Unknown;
}
Console.WriteLine("\n=======================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("-=- Property Creation -=-");
Console.WriteLine("------------------------");
try
{
Console.WriteLine("\nTypes of Properties");
Console.WriteLine("1. Condominium");
Console.WriteLine("2. Townhouse");
Console.WriteLine("3. Single Family");
Console.Write("Enter Type of Property: ");
propType = char.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the type of property is invalid");
}
switch (propType)
{
case '1':
CreateCondominium();
break;
case '2':
CreateTownhouse();
break;
case '3':
CreateSingleFamily();
C# 3.0 Practical Learning 751
break;
default:
Console.WriteLine("Invalid Choice!!!");
break;
}
}
Condo.PropertyNumber = strPropertyNumber;
Condo.Condition = GetPropertyCondition();
try
{
Console.Write("\nHow many bedrooms? ");
Condo.Bedrooms = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
Condo.Bathrooms =
float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid value");
}
try
{
Console.Write("Year built: ");
Condo.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("Condominium Value: ");
Condo.Value = decimal.Parse(Console.ReadLine());
C# 3.0 Practical Learning 752
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
Condominiums.Add(Condo);
ShowTitle();
ShowCondominium();
SaveCondominium();
}
this.TownHome.PropertyNumber = strPropertyNumber;
this.TownHome.Condition = GetPropertyCondition();
try
{
Console.Write("\nHow many stories (levels)? ");
this.TownHome.Stories =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The number of stories " +
"you entered is not valid");
}
try
{
Console.Write("How many bedrooms? ");
this.TownHome.Bedrooms =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
this.TownHome.Bathrooms =
float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid bathroom number.");
}
try
{
Console.Write("Year built: ");
this.TownHome.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("Is it community managed (y/n)? ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
this.TownHome.IsCommunityManaged = true;
else
this.TownHome.IsCommunityManaged = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Answer");
}
try
{
Console.Write("Property Value: ");
this.TownHome.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
Townhouses.Add(this.TownHome);
ShowTitle();
ShowTownhouse();
SaveTownhouse();
}
this.House.PropertyNumber = strPropertyNumber;
House.Condition = GetPropertyCondition();
try
{
Console.Write("How many bedrooms? ");
House.Bedrooms =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
House.Bathrooms =
float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid number of bathrooms");
}
try
{
Console.Write("Does it have an indoor " +
"car garage (y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Indoor Car Garage Answer");
}
try
{
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Basement Answer");
C# 3.0 Practical Learning 755
}
try
{
Console.Write("Year built: ");
House.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("House Value: ");
House.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
SingleFamilies.Add(House);
ShowTitle();
ShowSingleFamily();
SaveSingleFamily();
}
try
{
fsTown = new FileStream(strFilename,
FileMode.Create,
FileAccess.Write);
bfTown.Serialize(fsTown, Townhouses);
}
finally
{
fsTown.Close();
}
}
try
{
fsHouse = new FileStream(strFilename,
FileMode.Create,
FileAccess.Write);
bfHouse.Serialize(fsHouse,
SingleFamilies);
}
finally
{
fsHouse.Close();
}
}
}
}
namespace RealEstate5
{
public class Program
{
static void Main(string[] args)
{
var answer = 'q';
var listing = new PropertyManagement();
switch (answer)
{
case '1':
listing.CreateProperty();
break;
default:
break;
}
} while(answer == '1');
Console.WriteLine();
}
}
}
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 1
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
C# 3.0 Practical Learning 760
Enter Type of Property: 2
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 1
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 3
=//= Altair Realty =//=
-=- Property Creation -=-
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 1
C# 3.0 Practical Learning 761
How many stories (levels)? 1
How many bedrooms? 1
How many bathrooms? 1
Does it have an indoor car garage (y/n): n
Is the basement finished(y/n): n
Year built: 1960
House Value: 30000
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
----------------------------------
Property #: 000003
Property Type: Single Family
Stories: 1
Has Indoor Car Garage: False
Finished Basement: False
Condition: Excellent
Bedrooms: 1
Bathrooms: 1.00
Year Built: 1960
Market Value: $30,000.00
----------------------------------
When using a list, at any time, you should be able to know the number of items that the
list contains. This information is provided by the ArrayList.Count property. The
Capacity and the Count have this in common: the value of each increases as the list
grows and the same value decreases if the list shrinks. It is important to know that,
although they look alike, there are various differences between the capacity of a list and
the number of items it contains. Capacity is a read/write property. This means that, as
we saw above, you can assign a value to the capacity to fix the number of items that
the list can contain. You can also retrieve the value of the Capacity. The Count is read-
only because it is used by the compiler to count the current number of items of the
items and this counting is performed without your intervention.
Item Retrieval
Once a list is ready, you can perform different types of operations on it. Besides adding
items, one of the most regular operations performed on a list consists of locating and
retrieving its items. You have various options. To retrieve a single item based on its
position, you can apply the square brackets of arrays to the variable. Like a normal
array, an ArrayList list is zero-based. Another issue to keep in mind is that the
ArrayList[] returns an Object value. Therefore, you may have to cast this value to
your type of value to get it right.
C# 3.0 Practical Learning 762
Besides using the index to access an item from the list, ArrayList class implements the
IEnumerable.GetEnumerator() method. For this reason, you can use the foreach
loop to access each member of the collection.
namespace RealEstate5
{
public class PropertyManagement
{
private Condominium Condo;
private Townhouse TownHome;
private SingleFamily House;
ArrayList Condominiums;
ArrayList Townhouses;
ArrayList SingleFamilies;
string strPropertyNumber;
string strPropertiesDirectory;
public PropertyManagement()
{
Condo = new Condominium();
TownHome = new Townhouse();
House = new SingleFamily();
Condominiums = new ArrayList();
Townhouses = new ArrayList();
SingleFamilies = new ArrayList();
strPropertyNumber = "000000";
try
{
// If a directory for the properties has not yet
// been created, then create them
Directory.CreateDirectory(strPropertiesDirectory);
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The directory could not be created");
}
}
try
{
Console.WriteLine("\nProperties Conditions");
Console.WriteLine("1. Excellent");
Console.WriteLine("2. Good (may need minor repair)");
Console.WriteLine("3. Needs Repair");
Console.Write("4. In Bad Shape (property needs ");
Console.WriteLine("major repair or rebuild)");
Console.Write("Enter Property Condition: ");
condition = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the condition of the property is not
valid");
}
if (condition == 1)
return PropertyCondition.Excellent;
else if (condition == 2)
return PropertyCondition.Good;
else if (condition == 3)
return PropertyCondition.NeedsRepair;
else if (condition == 4)
return PropertyCondition.BadShape;
else
return PropertyCondition.Unknown;
}
Console.WriteLine("\n=======================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("-=- Property Creation -=-");
Console.WriteLine("------------------------");
try
{
fsProperties = new FileStream(strPropertiesDirectory +
@"\Condominiums.alr",
FileMode.Open,
FileAccess.Read);
Condominiums =
(ArrayList)bfProperties.Deserialize(fsProperties);
try
{
fsProperties = new FileStream(strPropertiesDirectory +
@"\Townhouses.alr",
FileMode.Open,
FileAccess.Read);
Townhouses =
(ArrayList)bfProperties.Deserialize(fsProperties);
try
{
fsProperties = new FileStream(strPropertiesDirectory +
@"\SingleFamilies.alr",
FileMode.Open,
FileAccess.Read);
SingleFamilies =
(ArrayList)bfProperties.Deserialize(fsProperties);
if (found == true)
C# 3.0 Practical Learning 765
{
Console.WriteLine("A property with that " +
"number exists already");
return;
}
try
{
Console.WriteLine("\nTypes of Properties");
Console.WriteLine("1. Condominium");
Console.WriteLine("2. Townhouse");
Console.WriteLine("3. Single Family");
Console.Write("Enter Type of Property: ");
propType = char.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the type of property is invalid");
}
switch (propType)
{
case '1':
CreateCondominium();
break;
case '2':
CreateTownhouse();
break;
case '3':
CreateSingleFamily();
break;
default:
Console.WriteLine("Invalid Choice!!!");
break;
}
}
Condo.PropertyNumber = strPropertyNumber;
Condo.Condition = GetPropertyCondition();
try
{
Console.Write("\nHow many bedrooms? ");
Condo.Bedrooms = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
Condo.Bathrooms =
C# 3.0 Practical Learning 766
float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid value");
}
try
{
Console.Write("Year built: ");
Condo.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("Condominium Value: ");
Condo.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
Condominiums.Add(Condo);
ShowTitle();
ShowCondominium();
SaveCondominium();
}
this.TownHome.PropertyNumber = strPropertyNumber;
this.TownHome.Condition = GetPropertyCondition();
try
{
Console.Write("\nHow many stories (levels)? ");
this.TownHome.Stories =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The number of stories " +
"you entered is not valid");
C# 3.0 Practical Learning 767
}
try
{
Console.Write("How many bedrooms? ");
this.TownHome.Bedrooms =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
this.TownHome.Bathrooms =
float.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid bathroom number.");
}
try
{
Console.Write("Year built: ");
this.TownHome.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("Is it community managed (y/n)? ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
this.TownHome.IsCommunityManaged = true;
else
this.TownHome.IsCommunityManaged = false;
}
C# 3.0 Practical Learning 768
catch (FormatException)
{
Console.WriteLine("Invalid Answer");
}
try
{
Console.Write("Property Value: ");
this.TownHome.Value =
decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
Townhouses.Add(this.TownHome);
ShowTitle();
ShowTownhouse();
SaveTownhouse();
}
this.House.PropertyNumber = strPropertyNumber;
House.Condition = GetPropertyCondition();
try
{
Console.Write("\nHow many stories (levels)? ");
House.Stories = short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The number of stories you " +
"entered is not allowed");
}
try
{
Console.Write("How many bedrooms? ");
House.Bedrooms =
short.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered for " +
"the number of bedrooms is not good");
}
try
{
Console.Write("How many bathrooms? ");
House.Bathrooms =
float.Parse(Console.ReadLine());
C# 3.0 Practical Learning 769
}
catch (FormatException)
{
Console.WriteLine("Invalid number of bathrooms");
}
try
{
Console.Write("Does it have an indoor " +
"car garage (y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.IndoorGarage = true;
else
House.IndoorGarage = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Indoor Car Garage Answer");
}
try
{
Console.Write("Is the basement finished(y/n): ");
answer = char.Parse(Console.ReadLine());
if ((answer == 'y') || (answer == 'Y'))
House.FinishedBasement = true;
else
House.FinishedBasement = false;
}
catch (FormatException)
{
Console.WriteLine("Invalid Basement Answer");
}
try
{
Console.Write("Year built: ");
House.YearBuilt =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The house cannot have " +
"built in that year");
}
try
{
Console.Write("House Value: ");
House.Value = decimal.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Property Value");
}
SingleFamilies.Add(House);
ShowTitle();
ShowSingleFamily();
SaveSingleFamily();
}
C# 3.0 Practical Learning 770
public void ShowTitle()
{
Console.WriteLine("==================================");
Console.WriteLine(" =//=//= Altair Realty =//=//=");
Console.WriteLine("-=-=-=- Properties Listing -=-=-=-");
}
try
{
fsCondo = new FileStream(strFilename,
FileMode.Create,
FileAccess.Write);
bfCondo.Serialize(fsCondo, Condominiums);
}
finally
{
fsCondo.Close();
}
}
try
{
fsTown = new FileStream(strFilename,
FileMode.Create,
FileAccess.Write);
bfTown.Serialize(fsTown, Townhouses);
}
C# 3.0 Practical Learning 772
finally
{
fsTown.Close();
}
}
try
{
fsHouse =
new FileStream(strFilename,
FileMode.Create,
FileAccess.Write);
bfHouse.Serialize(fsHouse, SingleFamilies);
}
finally
{
fsHouse.Close();
}
}
Console.WriteLine();
ShowTitle();
try
{
Console.WriteLine("What properties do you want to see?");
Console.WriteLine("1. One Particular Property");
Console.WriteLine("2. Condominiums Only");
Console.WriteLine("3. Townhouses Only");
Console.WriteLine("4. Single Families Only");
Console.WriteLine("5. All properties");
Console.WriteLine("6. None");
Console.Write("Your Choice? ");
choice = int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Selection");
}
switch (choice)
{
case 1:
ShowParticularProperty();
break;
case 2:
ShowCondominiums();
C# 3.0 Practical Learning 773
break;
case 3:
ShowTownhouses();
break;
case 4:
ShowSingleFamilies();
break;
case 5:
ShowCondominiums();
ShowTownhouses();
ShowSingleFamilies();
break;
default:
break;
}
}
Console.WriteLine("\n=======================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("------------------------");
try
{
fsProperty = new FileStream(strPropertiesDirectory +
@"\Condominiums.alr",
FileMode.Open,
FileAccess.Read);
Condominiums =
(ArrayList)bfProperty.Deserialize(fsProperty);
try
{
fsProperty = new FileStream(strPropertiesDirectory +
@"\Townhouses.alr",
FileMode.Open,
C# 3.0 Practical Learning 774
FileAccess.Read);
Townhouses =
(ArrayList)bfProperty.Deserialize(fsProperty);
try
{
fsProperty = new FileStream(strPropertiesDirectory +
@"\SingleFamilies.alr",
FileMode.Open,
FileAccess.Read);
SingleFamilies =
(ArrayList)bfProperty.Deserialize(fsProperty);
if (found == false)
{
Console.WriteLine("No property with that " +
"number was found in the database");
return;
}
}
try
{
C# 3.0 Practical Learning 775
fsProperty = new FileStream(strPropertiesDirectory +
@"\Condominiums.alr",
FileMode.Open,
FileAccess.Read);
Condominiums =
(ArrayList)bfProperty.Deserialize(fsProperty);
Console.WriteLine("\n=================================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("----------------------------------");
Console.WriteLine("Condominiums Listing");
Console.WriteLine("----------------------------------");
foreach (Condominium c in Condominiums)
{
Console.WriteLine("Property #: {0}",
c.PropertyNumber);
Console.WriteLine("Condition: {0}",
c.Condition);
Console.WriteLine("Bedrooms: {0}",
c.Bedrooms);
Console.WriteLine("Bathrooms: {0:F}",
c.Bathrooms);
Console.WriteLine("Year Built: {0}",
c.YearBuilt);
Console.WriteLine("Handicapped Accessible Building:
{0}",
Condo.HandicapAccessible);
Console.WriteLine("Market Value: {0:C}",
c.Value);
Console.WriteLine("----------------------------------");
}
}
finally
{
fsProperty.Close();
}
}
try
{
fsProperty = new FileStream(strPropertiesDirectory +
@"\Townhouses.alr",
FileMode.Open,
FileAccess.Read);
Townhouses =
(ArrayList)bfProperty.Deserialize(fsProperty);
Console.WriteLine("\n=================================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("----------------------------------");
Console.WriteLine("Townhouses Listing");
Console.WriteLine("----------------------------------");
foreach (Townhouse t in Townhouses)
{
C# 3.0 Practical Learning 776
Console.WriteLine("Property #: {0}",
t.PropertyNumber);
Console.WriteLine("Stories: {0}",
t.Stories);
Console.WriteLine("Has Indoor Car Garage: {0}",
t.IndoorGarage);
Console.WriteLine("Finished Basement: {0}",
t.FinishedBasement);
Console.WriteLine("Condition: {0}",
t.Condition);
Console.WriteLine("Bedrooms: {0}",
t.Bedrooms);
Console.WriteLine("Bathrooms: {0:F}",
t.Bathrooms);
Console.WriteLine("Year Built: {0}",
t.YearBuilt);
Console.WriteLine("Community Managed? {0}",
t.IsCommunityManaged);
Console.WriteLine("Market Value: {0:C}",
t.Value);
Console.WriteLine("----------------------------------");
}
}
finally
{
fsProperty.Close();
}
}
try
{
fsProperty = new FileStream(strPropertiesDirectory +
@"\SingleFamilies.alr",
FileMode.Open,
FileAccess.Read);
SingleFamilies =
(ArrayList)bfProperty.Deserialize(fsProperty);
Console.WriteLine("\n================================");
Console.WriteLine(" =//= Altair Realty =//=");
Console.WriteLine("----------------------------------");
Console.WriteLine("Single Families Listing");
Console.WriteLine("----------------------------------");
foreach (SingleFamily s in SingleFamilies)
{
Console.WriteLine("Property #: {0}",
s.PropertyNumber);
Console.WriteLine("Stories: {0}",
s.Stories);
Console.WriteLine("Has Indoor Car Garage: {0}",
s.IndoorGarage);
Console.WriteLine("Finished Basement: {0}",
s.FinishedBasement);
Console.WriteLine("Condition: {0}",
C# 3.0 Practical Learning 777
s.Condition);
Console.WriteLine("Bedrooms: {0}",
s.Bedrooms);
Console.WriteLine("Bathrooms: {0:F}",
s.Bathrooms);
Console.WriteLine("Year Built: {0}",
s.YearBuilt);
Console.WriteLine("Market Value: {0:C}",
s.Value);
Console.WriteLine("----------------------------------");
}
}
finally
{
fsProperty.Close();
}
}
}
}
namespace RealEstate5
{
public class Program
{
static void Main(string[] args)
{
var answer = 'q';
var listing = new PropertyManagement();
Console.WriteLine();
}
}
}
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 1
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 2
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 2
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 1
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 3
=//= Altair Realty =//=
-=- Property Creation -=-
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 1
=======================
=//= Altair Realty =//=
-=- Property Creation -=-
------------------------
Types of Properties
1. Condominium
2. Townhouse
3. Single Family
Enter Type of Property: 3
=//= Altair Realty =//=
-=- Property Creation -=-
Properties Conditions
1. Excellent
2. Good (may need minor repair)
3. Needs Repair
4. In Bad Shape (property needs major repair or rebuild)
Enter Property Condition: 3
5. Execute the application again and test different options. Here are examples:
================================
=//= Altair Realty =//=
----------------------------------
What do you want to do?
1. Create a property
2. Show the properties
3. Delete a property
0. Quit
Your Choice? 2
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
What properties do you want to see?
1. One Particular Property
2. Condominiums Only
3. Townhouses Only
4. Single Families Only
5. All properties
6. None
Your Choice? 1
=======================
=//= Altair Realty =//=
------------------------
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
What properties do you want to see?
1. One Particular Property
2. Condominiums Only
3. Townhouses Only
4. Single Families Only
5. All properties
C# 3.0 Practical Learning 783
6. None
Your Choice? 3
=================================
=//= Altair Realty =//=
----------------------------------
Townhouses Listing
----------------------------------
Property #: 000002
Stories: 1
Has Indoor Car Garage: False
Finished Basement: False
Condition: Excellent
Bedrooms: 1
Bathrooms: 1.00
Year Built: 1960
Community Managed? False
Market Value: $20,000.00
----------------------------------
Property #: 512664
Stories: 3
Has Indoor Car Garage: False
Finished Basement: True
Condition: Excellent
Bedrooms: 3
Bathrooms: 2.50
Year Built: 1992
Community Managed? True
Market Value: $435,660.00
----------------------------------
What do you want to do?
1. Create a property
2. Show the properties
3. Delete a property
0. Quit
Your Choice? 2
==================================
=//=//= Altair Realty =//=//=
-=-=-=- Properties Listing -=-=-=-
What properties do you want to see?
1. One Particular Property
2. Condominiums Only
3. Townhouses Only
4. Single Families Only
5. All properties
6. None
Your Choice? 4
================================
=//= Altair Realty =//=
----------------------------------
Single Families Listing
----------------------------------
Property #: 000003
Stories: 1
Has Indoor Car Garage: False
Finished Basement: False
Condition: Excellent
Bedrooms: 1
C# 3.0 Practical Learning 784
Bathrooms: 1.00
Year Built: 1960
Market Value: $30,000.00
----------------------------------
Property #: 802664
Stories: 3
Has Indoor Car Garage: True
Finished Basement: True
Condition: Excellent
Bedrooms: 4
Bathrooms: 3.50
Year Built: 1995
Market Value: $755,820.00
----------------------------------
Property #: 693524
Stories: 2
Has Indoor Car Garage: False
Finished Basement: False
Condition: NeedsRepair
Bedrooms: 3
Bathrooms: 2.50
Year Built: 1964
Market Value: $515,665.00
----------------------------------
What do you want to do?
1. Create a property
2. Show the properties
3. Delete a property
0. Quit
Your Choice? 0
Item Location
Instead of the square brackets that allow you to retrieve an item based on its position,
you can look for an item based on its complete definition. You have various options. You
can first "build" an item and ask the compiler to check whether any item in the list
matches your definition. To perform this search, you can call the
ArrayList.Contains() method. Its syntax is:
The item to look for is passed as argument to the method. The compiler would look for
exactly the item, using its definition, in the list. If any detail of the argument fails to
match any item of the ArrayList list, the method would return false. If all
characteristics of the argument correspond to an item of the list, the method returns
true.
Item Deletion
As opposed to adding an item to a list, you may want to remove one. To perform this
operation, you have various options. You can ask the compiler to look for an item in the
list and if, or once, the compile finds it, it would delete the item. To perform this type of
deletion, you can call the ArrayList.Remove() method. Its syntax is:
public virtual void Remove(object obj);
This method accepts as argument the item that you want to delete from the list. To
perform this operation, the list must not be read-only.
The Remove() method allows you to specify the exact item you want to delete from a
list. Another option you have consists of deleting an item based on its position. This is
done using the RemoveAt() method whose syntax is:
public virtual void RemoveAt(int index);
With this method, the position of the item is passed as argument. If the position is not
valid because either it is lower or higher than the current Count, the compiler would
throw an ArgumentOutOfRangeException exception.
To remove all items from a list at once, you can call the ArrayList.Clear() method.
Its syntax is:
public virtual void Clear();
Generic Methods
Introduction
As is usually done, imagine you want to pass different types of values to various
methods of a class to primarily accomplish the same purpose. You may be tempted to
overloaded a method in various versions as follows:
using System;
{
// Display the value of an integer
public void Show(int value)
{
Console.WriteLine(value);
}
{
static int Main()
{
var exo = new Generator();
return 0;
}
}
We passed a constant value directly to the method when we called it. Remember that
you can also first declare a variable, assign it a value, and then pass that variable to the
method. Here are examples:
public class Exercise
{
static int Main()
{
var exo = new Generator();
return 0;
}
}
Although this is based on the concept of method overloading, another way you can solve
this type of problem is to create one method that doesn't know the type of value that
would be passed to it but the method is equipped to process the value appropriately.
Based on the above program, you can create one method that takes an argument and it
displays its value. To do this, at the time you are defining the method, you only let it
know that it would receive an argument but you don't specify the type of value that it
will process. Such a method is referred to as generic.
2. To create a new class, on the main menu, click Project -> Add Class...
namespace CommercialStore1
{
public class StoreItem
{
public class CItem
{
public double Item;
public CItem Next;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return Size++;
}
return Current;
}
namespace CommercialStore1
C# 3.0 Practical Learning 789
{
public class Program
{
static void Main()
{
StoreItem exo = new StoreItem();
StoreItem.CItem Part;
exo.ShowItem(One.Item);
}
Number of Items: 6
A generic method is a method that can process a value whose type is known only when
the variable is accessed. To create a generic method, on the right side of the name of
the method, type the <> operator. Inside of this operator, enter a letter or a name,
which is referred to as parameter type. Here is an example:
public class Generator
{
public void Show<TypeOfValue>()
{
}
}
One of the ways you can use the parameter type is to pass an argument to the method.
You do this by preceding the name of the argument with the parameter type. Here is an
example:
public class Generator
{
public void Show<TypeOfValue>(TypeOfValue value)
{
}
}
In the body of the method, you can process the argument as you see fit. At a minimum,
and based on our earlier program, you can simply display the value by passing it to the
Console.WriteLine() method. Here is an example:
By tradition, most programmers and most documents use the letter T for the parameter
type.
return 0;
}
}
As an alternative, you can type the name of the method, followed by angle brackets.
Inside of the brackets, enter the data type of the value that will be processed. After the
angle brackets, open the parentheses and, inside of them, type the constant value that
will be processed. Here are examples:
using System;
return 0;
}
}
You can also declare the value as a constant before passing it to the method.
1. To specify the parameter type of a generic method when calling it, change the
Main() method as follows:
class Program
{
static void Main()
{
. . .
exo.ShowItem<double>(One.Item);
}
Just like a method can take one argument, it can take various generic parameters. You
can pass one argument as a known type and the other as a generic type. Here is an
example:
using System;
exo.Show<int>("Integer", 246);
exo.Show<char>("Character", 'G');
exo.Show<double>("Decimal", 355.65);
return 0;
}
}
Although we directly passed the values to the method when calling it, you can first
declare a variable before passing it to the method. Here are examples:
using System;
message = "Character";
const char cValue = 'G';
exo.Show<char>(message, cValue);
message = "Decimal";
const double dValue = 355.65;
exo.Show<double>(message, dValue);
return 0;
}
}
2. To create and use a method with various parameters, make the following changes:
namespace CommercialStore1
{
public class StoreItem
{
. . .
}
}
}
Number of Items: 6
As seen above, you can pass different arguments to a method. You can also pass
different parameter types, in any appropriate order of your choice, to a method. To pass
two parameter types to a method, inside its <> operator, enter the names of two
parameter types separated by a comma. Here is an example:
public class Generator
{
public void Show<FirstType, SecondType>()
{
}
}
If you want to use the parameter types, you can pass an argument for each to the
method. Remember that each parameter type represents a data type; so you can use it
as the type of an argument. Here are examples:
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
}
}
In the body of the method, you can then use the arguments as you see fit. For example,
you can display their values by passing them to the Console.WriteLine() method.
Here is an example:
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
Console.WriteLine("First: {0}\nSecond: {1}\n", first, second);
}
}
return 0;
}
}
An alternative is to specify the type of each argument. To do this, inside the <>
operator on the right side of the name of the method, enter the data types separated by
a comma. Here are examples:
using System;
return 0;
}
}
First: 85
Second: G
First: 42.5
Second: 25.05
Notice that the arguments can be of the same type or different types. It is up to you to
determine the type of a particular argument when calling the method.
Generic Classes
Introduction
Like a method, a class can be created as a generic. When a class is created as generic, it
is asked to process a value wihtout knowing what type that value is. This means that the
class will known the type of value only when it is called.
To create a generic class, on the right side of the name of the class, type the <>
operator and enter a name for the parameter type. Here is an example:
public class Exercise<TypeOfValue>
{
}
This parameter type is just a representative of a data type. As a data type, you can use
it to declare a variable in the body of the class. Here is an example:
public class Exercise<TypeOfValue>
{
public TypeOfValue value;
}
After declaring such a variable, you can use it in your application. For example, you can
access it outside of the class using the period operator. Inside of the class, one way you
can use the variable is to display its value using one of the methods of the class. Here is
an example:
1. To start a new program, on the main menu, click the File -> New Project ...
2. Click Console Application. Set the Name to CommercialStore2 and press Enter
3. To create a new class, on the main menu, click Project -> Add Class...
namespace CommercialStore2
{
public class ListOfItems
{
public class CItem
{
public double Item;
public CItem Next;
}
public ListOfItems()
{
Head = null;
Size = 0;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
C# 3.0 Practical Learning 799
return Size++;
}
return Current;
}
}
}
namespace CommercialStore2
{
public class Program
{
static void Main()
{
ListOfItems exo = new ListOfItems();
ListOfItems.CItem Part;
Number of Items: 6
After creating a generic class, you can use it. One way to do this, as we have learned in
previous lessons, consists of declaring a variable for it. In previous lessons, to declare a
variable of a class, we would write:
Exercise exo = new Exercise();
If the class is generic, on the right side, type the <> operator. Inside of this operator,
enter the data type that will be processed as the parameter type of the generic class.
Here is an example:
using System;
return 0;
}
}
You can also declare a variable of a generic type using the var keyword. To do this, use
var on the left side of the variable name, omit the <> operator and the data type. This
would be done as follows:
public class Exercise
{
static int Main()
{
var exo = new Generator<int>();
return 0;
}
}
After declaring the variable, you can then access the member(s) of the class using the
period operator. Here are examples:
using System;
return 0;
}
}
We saw that you could declare a variable of a parameter type in the generic class.
Another way you can use it is to pass it as an argument to a method and make the
argument a parameter type. As seen previously, you can use the argument as you see
fit. For example, you can display its value to the console. Here is an example:
using System;
return 0;
}
}
In the same way, you can pass the parameter type to a constructor of the class. Here is
an example:
public class Generator<TypeOfValue>
{
private TypeOfValue val;
public Exercise(TypeOfValue v)
{
val = v;
}
}
Besides, or as opposed to, passing a parameter type, you can create a method that
returns a parameter type. Once again, you can primarily observe the rules we reviewed
for returning a value from a method. Here is an example:
using System;
public Generator(TypeOfValue v)
{
val = v;
}
return 0;
}
}
namespace CommercialStore2
{
public class ListOfItems
{
public class CItem<T>
{
public double Item;
public CItem<T> Next;
}
public ListOfItems()
{
Head = null;
Size = 0;
}
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return Size++;
}
return Current;
}
}
}
namespace CommercialStore2
{
public class Program
{
static void Main()
{
ListOfItems exo = new ListOfItems();
ListOfItems.CItem<double> Part;
You can create a property that is of the parameter type of the generic class. There is no
significant rule to follow when creating the property, except that you should remember
that, at the time you are creating the property, the class doesn't know the type of the
parameter. Here is an example:
using System;
exo.Value = 246;
exo.Show();
return 0;
}
}
If you know for sure that the parameters will be of the same type, you can use one
method to process both. Otherwise, you can declare the necessary members for each
type. You can also create a method that would take many arguments with each
argument of a particular type. Here are examples:
using System;
public T GetTValue()
{
return t;
}
When declaring a variable for the class, make sure you appropriately specify the list of
parameter types. Here are two examples:
public class Exercise
{
static int Main()
{
Generator<int, int> IntTypes = new Generator<int, int>();
IntTypes.SetTValue(246);
IntTypes.SetVValue(6088);
IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue());
return 0;
}
}
You can also declare the variable using the var keyword. To do this, on the left side of
the assignment operator, type only the var keyword and the name of the operator. Here
is an example:
public class Exercise
{
static int Main()
{
var IntTypes = new Generator<int, int>();
IntTypes.SetTValue(246);
IntTypes.SetVValue(6088);
IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue());
return 0;
}
}
If a generic class has more than one parameter type, they don't have to be of the same
type. At the time you are creating the class, you may not specify their types but you can
anticipate that they would be different. It is when you declare the variable that you
would need to determine their precise types.
So far, in our examples, we treated the parameter type as a primitive data type. A
parameter type can also be a formal class, either one that you created yourself or one
that exists as part of the C# language. When creating the generic class, you must follow
all the rules we have reviewed so far for generic classess. Here is such a simple class:
public class Generator
{
public void Show(TypeOfValue val)
{
Console.WriteLine("{0}\n", val.ToString());
}
}
As mentioned already, the class that would be processed by the generic one must have
been previously created so it can be used as a parameter. When declaring a variable of
the generic class, make sure you enter the name of the normal class in place of the
parameter type. Everything else is as we have done so far. Here is an example:
using System;
Generator<FourSideGeometricFigure> exoRect =
new Generator<FourSideGeometricFigure>();
exoRect.Show(rect);
return 0;
}
}
You can also declare the variable using the var keyword. Here are examples:
public class Exercise
{
static int Main()
{
var sqr = new FourSideGeometricFigure();
sqr.Name = "Square";
sqr.Base = 36.82;
sqr.Height = 36.82;
var exoSquare = new Generator<FourSideGeometricFigure>();
exoSquare.Show(sqr);
Type: Rectangle
Base: 52.94
Height: 27.58
Area: 1460.0852
In the same way, you can create a generic class that takes more than one parameter
Introduction
Consider the following geometric figures:
Notice that these are geometric figures with each having four sides. From what we know
so far, we can create a base class to prepare it for inheritance. If the class is very
general, we can make it a generic one. We can set a data type as an unknown type,
anticipating that the dimensions of the figure can be considered as integer or double-
precision types. Here is an example:
using System;
public Quadrilateral()
{
_name = "Quadrilateral";
}
// Rectangle, in meters
var BasketballStadium = new Quadrilateral<Byte>();
BasketballStadium.Name = "Basketball Stadium";
BasketballStadium.Base = 15;
BasketballStadium.Height = 28;
BasketballStadium.ShowCharacteristics();
Console.WriteLine();
return 0;
}
}
If you have a generic class that can serve as a foundation for another class, you can
derive one class from the generic one. To do this, use the formula we apply when
deriving a class but follow the name of each class with <>. Inside of the <> operator,
enter the same identifier to indicate that the class is a generic type that is based on
another generic class. Here is an example:
public class Square<T> : Quadrilateral<T>
{
}
In the body of the new class, you can use the parameter type as you see fit. For
example, you can declare some member variables of that type. You can create methods
that return the parameter type or you can pass arguments of the parameter type. When
implementing the methods of the new class, use the member variables of the parameter
and the argument(s) based on the parameter type as you see fit. You can then declare a
variable of the class and use it as we done so far for other generic classes. Here is an
example:
using System;
public Quadrilateral()
{
_name = "Quadrilateral";
}
plate.Name = "Plate";
plate.Base = 15;
plate.Height = 28;
plate.ShowCharacteristics();
Console.WriteLine();
return 0;
}
}
As done for a generic class, you can create a generic interface that would serve as the
base for generic classes. To proceed, when creating the interface, follow its name with a
Since this is a generic interface, like an interface class, when deriving a class from it,
follow the formula we reviewed for inheriting from a generic class. Here is an example:
using System;
When implementing the derived class, you must observe all rules that apply to interface
derivation. Here is an example:
using System;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
}
Console.WriteLine();
return 0;
}
}
In the same way, you can derive a generic class from another generic class that derived
from a generic interface.
Then imagine you derive a regular class from it. Here is an example:
using System;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
_rad = 0.00;
}
public Round(string name, double radius)
{
C# 3.0 Practical Learning 817
_name = name;
_rad = radius;
}
Console.WriteLine();
return 0;
}
}
You may be tempted to derive just any type of class from it. One of the features of
generics is that you can create a class that must implement the functionality of a certain
abstract class of your choice. For example, when creating a generic class, you can oblige
it to implement the functionality of a certain interface or you can make sure that the
class is derived from a specific base class. This would make sure that the generic class
surely contains some useful functionality.
To create a constraint on a generic class, after the <TypeName> operator, type where
TypeName : followed by the rule that the class must follow. For example, you may want
the generic class to implement the functionality of a pre-defined class. You can create
the generic class as follows:
public interface IGeometry
{
}
After creating the class, you must implement the virtual members of the where
class/interface, using the rules of generic classes, the way we have done it so far. When
declaring a variable for the generic class, in its <> operator, you must enter an object of
the base class. Here is an example:
using System;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
_rad = 0.00;
}
public Round(string name, double radius)
{
_name = name;
_rad = radius;
}
public Sphere() { }
public Sphere(T fig)
{
_t = fig;
}
public T Figure
{
get { return _t; }
set { _t = value; }
}
}
rnd.Name = "Circle";
rnd.Radius = 60.12;
Console.WriteLine();
return 0;
}
}
You can also create a constraint so that a generic class implements an interface.
Introduction
Files
A file is a series of bytes of data that are arranged in a particular manner to produce a
usable document. For easy storage, location, and management, the bytes are stored
on a medium such as a hard disc, a floppy disc, a compact disc, or any valid and
supported type of storage. When these bytes belong to a single but common entity and
hold values that are stored on a medium, the group is referred to as a file.
For greater management, files can be stored in a parent object called a directory or a
folder. Since a file is a unit of storage and it stores information, it has a size, which is
the number of bits it uses to store its values. To manage it, a file has a location also
called a path that specifies where and/or how the file can be retrieved. Also, for better
management, a file has attributes (characteristics) that indicate what can be done on
the file or that provide specific information that the programmer or the operating
system can use when dealing with the file.
Streams
File processing consists of creating, storing, and/or retrieving the contents of a file from
a recognizable medium. For example, it is used to save word-processed files to a hard
To create a file, a user must first decide where it would be located: this is a
requirement. A file can be located on the root drive. Alternatively, a file can be
positioned inside of an existing folder. Based on security settings, a user may not be
able to create a file just anywhere in the (file system of the) computer. Once the user
has decided where the file would reside, there are various means of creating files that
the users are trained to use. When creating a file, the user must give it a name following
the rules of the operating system combined with those of the file system. The most
fundamental piece of information a file must have is a name.
Once the user has created a file, whether the file is empty or not, the operating system
assigns basic pieces of information to it. Once a file is created, it can be opened,
updated, modified, renamed, etc.
Streaming Prerequisites
Introduction
To support file processing, the .NET Framework provides the System.IO namespace
that contains many different classes to handle almost any type of file operation you may
need to perform. Therefore, to perform file processing, you can include the System.IO
namespace in your project.
The parent class of file processing is Stream. With Stream, you can store data to a
stream or you can retrieve data from a stream. Stream is an abstract class, which
means that you cannot use it to declare a variable in your application. As an abstract
class, Stream is used as the parent of the classes that actually implement the necessary
operations. You will usually use a combination of classes to perform a typical operation.
For example, some classes are used to create a stream object while some others are
used to write data to the created stream.
1. Start Microsoft Visual C# and create a new Console Application named IceCream3
2. To save the project, on the Standard toolbar, click the Save All button
5. To create a new class, on the main menu, click Project -> Add Class...
namespace IceCream3
{
delegate void Request();
if ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length))
Console.WriteLine("Invalid Choice - Try Again!");
} while ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length));
}
namespace IceCream3
{
public class Program
{
static void Main(string[] args)
{
var ic = new IceCream();
var process = new Request(ic.ProcessAnOrder);
process();
}
}
}
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream Order
-----------------------------------
Flavor: Chocolate Chip
Container: Bowl
Ingredient: Cookies
Scoops: 3
Total Price: $3.60
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Before performing file processing, one of your early decisions will consist of specifying
the type of operation you want the user to perform. For example, the user may want to
create a brand new file, open an existing file, or perform a routine operation on a file. In
all or most cases, whether you are creating a new file or manipulating an existing one,
you must specify the name of the file. You can do this by declaring a string variable
but, as we will learn later on, most classes used to create a stream can take a string that
represents the file.
If you are creating a new file, there are certainly some rules you must observe. The name of
a file follows the directives of the operating system. On MS DOS and Windows 3.X (that is,
prior to Microsoft Windows 9X), the file had to use the 8.3 format. The actual name had to
have a maximum of 8 characters with restrictions on the characters that could be used. The
user also had to specify three characters after a period. The three characters, known as the
C# 3.0 Practical Learning 828
file extension, were used by the operating system to classify the file. That was all necessary
for those 8-bit and 16-bit operating systems. Various rules have changed. For example, the
names of folders and files on Microsoft Windows >= 95 can have up to 255 characters. The
extension of the file is mostly left to the judgment of the programmer but the files are still
using extensions. Applications can also be configured to save different types of files; that is,
files with different extensions.
At the time of this writing, the rules for file names for Microsoft Windows were
on the MSDN web site at Windows Development\Windows Base
Services\Files and I/O\SDK Documentation\Storage\Storage Overview\File
Management\Creating, Deleting, and Maintaining Files\Naming a File (because
it is a web site and not a book, its pages can change anytime).
Based on this, if you declare a string variable to hold the name of the file, you can
simply initialize the variable with the necessary name and its extension. Here is an
example:
using System;
return 0;
}
}
1. Access the IceCream.cs file and add a new internal method named SaveOrder of
type void as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IceCream3
{
// This class is used to create and manage an Ice Cream
// and to process an order
public sealed class IceCream
{
. . . No Change
namespace IceCream3
{
public class Program
{
static void Main(string[] args)
{
var ic = new IceCream();
var process = new Request(ic.ProcessAnOrder);
process();
If you declare a string as above, the file will be created in the folder as the application.
Otherwise, you can create your new file anywhere in the hard drive or on another
medium. To do that, you must provide a complete path where the file will reside. A path
is a string that specifies the drive (such as A:, C:, or D:, etc). The sections of a complete
path are separated by a backslash. For example, a path can be made of a folder
followed by the name of the file. An example would be
C:\Palermo.tde
A path can also consist of a drive followed by the name of the folder in which the file will
be created. Here is an example:
C:\Program Files\Palermo.tde
In Lesson 2, we saw that the backslash character is used to create or manage escape
sequences and it can be included in a string value to make up an escape sequence.
Because of this, every time you include a backslash in a string, the compiler thinks that
you are trying to provide an escape sequence. In this case, if the combination of the
backslash and the character that follows the backslash is not recognized as an escape
sequence, you would get an error. To solve this problem, you have two alternatives. To
indicate that the backslash must be considered as a character in its own right, you can
double it. Here are examples:
using System;
return 0;
}
}
Alternative, you can keep one backslash in each placeholder but precede the value of
the string with the @ symbol. Here is an example:
using System;
return 0;
}
}
In the same way, you can declare a string variable to represent the name of an
existing file that you plan to use in your program. You can also represent its path.
When providing a path to the file, if the drive you specify doesn't exist or cannot be
read, the compiler would consider that the file doesn't exist. If you provide folders that
don't exist in the drive, the compiler would consider that the file doesn't exist. This also
means that the compiler will not create the folder(s) (the .NET Framework provides all
means to create a folder but you must ask the compiler to create it; simply specifying a
folder that doesn't exist will not automatically create it, even if you are creating a new
file). Therefore, it is your responsibility to make sure that either the file or the path to
the file is valid. As we will see in the next section, the compiler can check the existence
of a file or path.
Introduction
The primary support of a file as an object is provided by a .NET Framework class called
File. This static class is equipped with various types of (static) methods to create, save,
open, copy, move, delete, or check the existence of a file.
File Existence
One of the valuable operations that the File class can perform is to check the existence
of the file you want to use. For example, if you are creating a new file, you may want to
make sure it doesn't exist already because if you try to create a file that exists already,
the compiler may first delete the old file before creating the new one. This could lead to
unpredictable result, especially because such a file is not sent to the Recycle Bin. On the
other hand, if you are trying to open a file, you should first make sure the file exists,
otherwise the compiler will not be able to open a file it cannot find.
To check the existence of a file, the File class provides the Exists method. Its syntax is:
public static bool Exists(string path);
If you provide only the name of the file, the compiler would check it in the folder of the
application. If you provide the path to the file, the compiler would check its drive, its
folder(s) and the file itself. In both cases, if the file exists, the method returns true. If
the compiler cannot find the file, the method returns false. It's important to know that if
you provided a complete path to the file, any slight mistake would produce a false
result.
namespace IceCream3
{
delegate void Request();
. . . No Change
if( File.Exists(Filename) )
{
Console.WriteLine("The file you entered exists already.");
Console.Write("Do you want to replace it(y/n)?" );
var Answer = char.Parse(Console.ReadLine());
return;
}
else
Console.WriteLine("Great");
}
if (File.Exists(Filename))
Console.WriteLine("The file would have been opened");
else
Console.WriteLine("The name you entered is not registered
" +
"in our previous orders");
}
}
}
namespace IceCream3
{
public class Program
{
static void Main(string[] args)
{
var ic = new IceCream();
var process = new Request(ic.ProcessAnOrder);
process();
File Creation
Besides checking the existence of the file, the File class can be used to create a new
file. To support this operation, the File class is equipped with the Create() method
that is overloaded with two versions as follows:
public static FileStream Create(string path);
public static FileStream Create(string path, int buffersize);
In both cases, the File.Create() method returns a Stream value, in this case a
FileStream value. As the File.Create() method indicates, it takes the name or path
of the file as argument. If you know or want to specify the size, in bytes, of the file, you
can use the second version.
To provide the same operation of creating a file, you can use the Open() method of the
File class. It is overloaded in three versions as follows:
Access to a File
In order to perform an operation on a file, you must specify to the operating system
how to proceed. One of the options you have is to indicate the type of access that will
FileAccess.ReadWrite: Existing data can be read from the file and new data be
written to the file
File Sharing
In standalone workstations, one person is usually able to access and open a file then
perform the necessary operations on it. In networked computers, you may create a file
that different people can access at the same time or you may make one file access
another file to retrieve information. For example, suppose you create an application for a
fast food restaurant that has two or more connected workstations and all workstations
save their customers orders to a common file. In this case, you must make sure that any
of the computers can access the file to save an order. An employee from one of these
workstations must also be able to open the file to retrieve a customer order for any
necessary reason. You can also create a situation where one file holds an inventory of
the items of a store and another file holds the customers orders. Obviously one file
would depend on another. Based on this, when an operation must be performed on a
file, you may have to specify how a file can be shared. This is done through the
FileShare enumerator.
Besides the access to the file, another option you will most likely specify to the operating
system is referred to as the mode of a file. It is specified through the FileMode
enumerator. The members of the FileMode Enumerator are:
FileMode.Append: If the file already exists, the new data will be added to its end.
If the file doesn't exist, it will be created and the new data will be added to it
FileMode.Create: If the file already exists, it will be deleted and a new file with
the same name will be created. If the file doesn't exist, then it will be created
FileMode.CreateNew: If the new already exists, the compiler will throw an error.
If the file doesn't exist, it will be created
Introduction
File streaming consists of performing one of the routine operations on a file, such as
creating it or opening it. This basic operation can be performed using a class called
FileStream. You can use a FileStream object to get a stream ready for processing. As
one of the most complete classes of file processing of the .NET Framework, FileStream
is equipped with all necessary properties and methods. To use it, you must first declare
a variable of it. The class is equipped with nine constructors.
One of the constructors (the second) of the FileStream class has the following syntax:
public FileStream(string path, FileMode mode);
This constructor takes as its first argument the name or the file or its path. The second
argument specifies the type of operation to perform on the file. Here is an example:
using System;
using System.IO;
1. To create a new stream, change the SaveOrder() method in the IceCream.cs file
and as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
if( File.Exists(Filename) )
{
Console.WriteLine("The file you entered exists
already.");
Console.Write("Do you want to replace it(y/n)?" );
var Answer = char.Parse(Console.ReadLine());
FileStream stmIceCream =
new FileStream(Filename, FileMode.Create);
return;
}
else
Console.WriteLine("Great");
}
Stream Writing
A streaming operation is typically used to create a stream. Once the stream is ready,
you can write data to it. The writing operation is perform through various classes. One
of these classes is BinaryWriter.
The BinaryWriter class can be used to write values of primitive data types ( char, int,
float, double, etc). To use a BinaryWriter value, you can first declare its variable. To
do this, you would use one of the class' three constructors. One of its constructors (the
second) has the following syntax:
return 0;
}
}
If you are initializing a variable while you are creating it, remember that you can use the
var keyword.
Most classes that are used to add values to a stream are equipped with a method called
Write. This is also the case for the BinaryWriter class. This method takes as
argument the value that must be written to the stream. The method is overloaded so
that there is a version for each primitive data type. Here is an example that adds strings
to a newly created file:
using System;
using System.IO;
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
return 0;
}
}
Stream Closing
When you use a stream, it requests resources from the operating system and uses them
while the stream is available. When you are not using the stream anymore, you should
free the resources and make them available again to the operating system so that other
services can use them. This is done by closing the stream.
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
wrtPersons.Close();
fstPersons.Close();
return 0;
}
}
namespace IceCream3
{
. . . No Change
bnwIceCream.Close();
stmIceCream.Close();
}
}
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream Order
-----------------------------------
Flavor: Caramel Au Lait
Container: Cup
Ingredient: M & M
Scoops: 2
C# 3.0 Practical Learning 841
Total Price: $3.10
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Stream Reading
As opposed to writing to a stream, you may want to read existing data from it. Before
doing this, you can first specify your intent to the streaming class using the FileMode
enumerator. This can be done using the FileStream class as follows:
using System;
using System.IO;
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
wrtPersons.Close();
fstPersons.Close();
*/
var fstPersons = new FileStream(Filename, FileMode.Open);
return 0;
}
}
Once the stream is ready, you can get prepared to read data from it. To support this,
you can use the BinaryReader class. This class provides two constructors. One of the
constructors (the first) has the following syntax:
public BinaryReader(Stream input);
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
wrtPersons.Close();
fstPersons.Close();
*/
var fstPersons = new FileStream(Filename, FileMode.Open);
var rdrPersons = new BinaryReader(fstPersons);
var strLine = "";
strLine = rdrPersons.ReadString();
Console.WriteLine(strLine);
strLine = rdrPersons.ReadString();
Console.WriteLine(strLine);
strLine = rdrPersons.ReadString();
Console.WriteLine(strLine);
strLine = rdrPersons.ReadString();
Console.WriteLine(strLine);
rdrPersons.Close();
fstPersons.Close();
return 0;
}
}
1. To be able to retrieve data from an existing file, change the IceCream.cs file as
follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace IceCream3
if ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length))
Console.WriteLine("Invalid Choice - Try Again!");
} while ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length));
}
bnwIceCream.Close();
stmIceCream.Close();
}
}
var stmIceCream =
new FileStream(Filename, FileMode.Open);
var bnrIceCream =
new BinaryReader(stmIceCream);
bnrIceCream.Close();
stmIceCream.Close();
}
else
Console.WriteLine("The name you entered is not " +
"registered in our previous orders");
}
}
}
namespace IceCream3
{
public class Program
{
static void Main(string[] args)
{
var ic = new IceCream();
var process = new Request(ic.ProcessAnOrder);
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream Order
-----------------------------------
Flavor: Butter Pecan
Container: Cup
Ingredient: No Ingredient
Scoops: 1
Total Price: $2.20
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
C# 3.0 Practical Learning 851
Do you want us to remember this order the next time
you come to get your Ice Cream (y/n)? y
Please enter your initials or the name we will use
to remember your order: DIC
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream Order
-----------------------------------
Flavor: Chunky Butter
Container: Bowl
Ingredient: Cookies
Scoops: 3
Total Price: $3.60
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Finally
So far, to handle exceptions, we were using the try, catch, and throw keywords.
These allowed us to perform normal assignments in a try section and then handle an
exception, if any, in a catch block.
In the previous lesson, we mentioned that, when you create a stream, the operating
system must allocate resources and dedicate them to the file processing operations.
Additional resources may be provided for the object that is in charge of writing to, or
reading from, the stream. We also saw that, when the streaming was over, we should
free the resources and give them back to the operating system. To do this, we called
the Close() method of the variable that was using resources.
More than any other assignment, file processing is in prime need of exception handling.
As we will see in the next section, during file processing, there are many things that can
go wrong. For this reason, the creation and/or management of streams should be
performed in a try block to get ready to handle exceptions that would occur. Besides
actually handling exceptions, the C# language provides a special keyword used free
resources. This keyword is finally.
The finally keyword is used to create a section of an exception. Like catch, a finally block
cannot exist by itself. It can be created following a try section. The formula used would
be:
try
{
}
finally
{
}
Based on this, the finally section has a body of its own, delimited by its curly
brackets. Like catch, the finally section is created after the try section. Unlike catch,
finally never has parentheses and never takes arguments. Unlike catch, the finally
section is always executed. Because the finally clause always gets executed, you can
include any type of code in it but it is usually appropriate to free the resources that were
allocated earlier. Here is an example:
using System;
using System.IO;
C# 3.0 Practical Learning 854
public class Program
{
static int Main(string[] args)
{
var Filename = "Members.clb";
var fstPersons = new FileStream(Filename, FileMode.Create);
var wrtPersons = new BinaryWriter(fstPersons);
try
{
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
}
finally
{
wrtPersons.Close();
fstPersons.Close();
}
return 0;
}
}
In the same way, you can use a finally section to free resources used when reading from
a stream:
using System;
using System.IO;
try
{
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
}
finally
{
wrtPersons.Close();
fstPersons.Close();
}*/
try
{
C# 3.0 Practical Learning 855
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
}
finally
{
rdrMembers.Close();
fstMembers.Close();
}
return 0;
}
}
Of course, since the whole block of code starts with a try section, it is used for
exception handling. This means that you can add the necessary and appropriate catch
section(s) but you don't have to.
2. To save the project, on the Standard toolbar, click the Save All button
5. To create a new class, on the main menu, click Project -> Add Class...
namespace IceCream4
{
delegate void Request();
if ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length))
Console.WriteLine("Invalid Choice - Try Again!");
} while ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length));
}
FileStream stmIceCream =
new FileStream(strFilename, FileMode.Create);
BinaryWriter bnwIceCream =
new BinaryWriter(stmIceCream);
try
{
stmIceCream =
new FileStream(strFilename, FileMode.Create);
C# 3.0 Practical Learning 861
bnwIceCream = new BinaryWriter(stmIceCream);
try
{
Console.WriteLine("\n=-= Ice Cream Vending Machine =-
=");
Console.WriteLine(" Saving Order: {0}", strFilename);
bnwIceCream.Write(Flavor[ChoiceFlavor - 1]);
bnwIceCream.Write(Container[ChoiceContainer - 1]);
bnwIceCream.Write(Ingredient[ChoiceIngredient - 1]);
bnwIceCream.Write(Scoops);
bnwIceCream.Write(TotalPrice);
}
finally
{
bnwIceCream.Close();
stmIceCream.Close();
}
}
}
string SelectedFlavor;
string SelectedContainer;
string SelectedIngredient;
FileStream stmIceCream =
new FileStream(strFilename, FileMode.Open);
BinaryReader bnrIceCream =
new BinaryReader(stmIceCream);
try
{
// Find out if this order was previously saved in the
machine
if (File.Exists(strFilename))
{
// If so, open it
SelectedFlavor = bnrIceCream.ReadString();
SelectedContainer = bnrIceCream.ReadString();
SelectedIngredient = bnrIceCream.ReadString();
Scoops = bnrIceCream.ReadInt32();
TotalPrice = bnrIceCream.ReadDecimal();
namespace IceCream4
C# 3.0 Practical Learning 863
{
public class Program
{
static void Main(string[] args)
{
var answer = 'n';
var ic = new IceCream();
var process = new Request(ic.ProcessAnOrder);
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
Ice Cream Order
-----------------------------------
Flavor: Cherry Coke
Container: Cup
Ingredient: No Ingredient
Scoops: 2
Total Price: $2.60
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
11.Execute the application and test it. Indicate that you want to open an existing file
Click Don't Send. Here is an example:
Do you want to re-order a previously saved order(y/n)? y
Please enter the name you previously gave to remember your order: Q4
One of the most important aspects of file processing is the name of the file that will be
dealt with. In some cases you can provide this name to the application or document. In
some other cases, you would let the user specify the name of the path. Regardless of
how the name of the file would be provided to the operating system, when this name is
acted upon, the compiler is asked to work on the file. If the file doesn't exist, the
operation cannot be carried. Furthermore, the compiler would throw an error. There are
many other exceptions that can be thrown as a result of something going bad during file
processing:
FileNotFoundException: The exception thrown when a file has not been found is of
type FileNotFoundException. Here is an example of handling it:
using System;
using System.IO;
try
{
wrtPersons.Write("James Bloch");
wrtPersons.Write("Catherina Wallace");
wrtPersons.Write("Bruce Lamont");
wrtPersons.Write("Douglas Truth");
}
finally
{
wrtPersons.Close();
fstPersons.Close();
}*/
try
{
var fstMembers =
new FileStream(Filename, FileMode.Open);
var rdrMembers = new BinaryReader(fstMembers);
try
{
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
strLine = rdrMembers.ReadString();
Console.WriteLine(strLine);
}
finally
{
rdrMembers.Close();
fstMembers.Close();
}
}
catch (FileNotFoundException ex)
{
Console.Write("Error: " + ex.Message);
Console.WriteLine(" May be the file doesn't exist " +
"or you typed it wrong!");
}
return 0;
}
}
1. To throw exceptions, change the file processing methods from the IceCream.cs file
as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace IceCream4
{
delegate void Request();
if ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length))
Console.WriteLine("Invalid Choice - Try Again!");
} while ((ChoiceIngredient < 1) ||
(ChoiceIngredient > Ingredient.Length));
}
try
{
// Find out if the user entered a name of a file
// that is already in the machine
if (File.Exists(strFilename))
{
char answer;
FileStream stmIceCream =
new FileStream(strFilename, FileMode.Create);
BinaryWriter bnwIceCream =
new BinaryWriter(stmIceCream);
try
{
try
{
stmIceCream = new FileStream(strFilename,
FileMode.Create);
bnwIceCream = new
BinaryWriter(stmIceCream);
try
{
Console.WriteLine("\n=-= Ice Cream Vending
Machine =-=");
Console.WriteLine(" Saving Order: {0}",
strFilename);
bnwIceCream.Write(Flavor[ChoiceFlavor - 1]);
bnwIceCream.Write(Container[ChoiceContainer -
1]);
bnwIceCream.Write(Ingredient[ChoiceIngredient -
1]);
bnwIceCream.Write(Scoops);
bnwIceCream.Write(TotalPrice);
}
finally
{
bnwIceCream.Close();
stmIceCream.Close();
}
}
}
catch (IOException ex)
{
Console.WriteLine("\nError: " + ex.Message);
Console.WriteLine("Operation Canceled: The file you want
" +
"to create exists already.");
}
}
C# 3.0 Practical Learning 874
internal void OpenOrder()
{
string strFilename;
string SelectedFlavor;
string SelectedContainer;
string SelectedIngredient;
try
{
FileStream stmIceCream =
new FileStream(strFilename, FileMode.Open);
BinaryReader bnrIceCream =
new BinaryReader(stmIceCream);
try
{
// Find out if this order was previously saved in the
machine
if (File.Exists(strFilename))
{
// If so, open it
SelectedFlavor = bnrIceCream.ReadString();
SelectedContainer = bnrIceCream.ReadString();
SelectedIngredient = bnrIceCream.ReadString();
Scoops = bnrIceCream.ReadInt32();
TotalPrice = bnrIceCream.ReadDecimal();
File Information
Introduction
In its high level of support for file processing, the .NET Framework provides the
FileInfo class. This class is equipped to handle all types of file-related operations
including creating, copying, moving, renaming, or deleting a file. FileInfo is based on
the FileSystemInfo class that provides information on characteristics of a file.
2. To take advantage of the Visual Basic rich library, in the Solution Explorer, under
WattsALoan2, right-click References and click Add Reference
3. In the Add Reference dialog box, click the .NET tab and click
Microsoft.VisualBasic
4. Click OK
namespace WattsALoan1
{
public class Program
{
static int Main(string[] args)
{
string EmployerName, ApplicantName;
string HomePhone, WorkPhone;
double LoanAmount = 0.00D, InterestRate = 0.0D;
double MonthlyPayment = 0.00D, Periods = 0D;
try
{
MonthlyPayment =
Microsoft.VisualBasic.Financial.Pmt(InterestRate / 12,
Periods, -LoanAmount,
0, Microsoft.VisualBasic.DueDate.BegOfPeriod);
}
catch (ArgumentException)
{
Console.WriteLine("Some invalid values were provided\n");
}
Console.WriteLine();
Console.WriteLine(" -=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine(" -=- Car Loan Application -=-");
Console.WriteLine(" -=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Applicant Information");
Console.WriteLine("Full Name: {0}", ApplicantName);
Console.WriteLine("Employer Name: {0}", EmployerName);
Console.WriteLine("Home Phone: {0}", HomePhone);
Console.WriteLine("Work Phone: {0}", WorkPhone);
Console.WriteLine("Loan Estimation");
Console.WriteLine("Loan Amount: {0:C}", LoanAmount);
Console.WriteLine("Interest Rate: {0:P}", InterestRate);
Console.WriteLine("Number of Months: {0:F}", Periods);
Console.WriteLine("Monthly Payment: {0:C}\n",
MonthlyPayment);
}
}
}
Applicant Information
Full Name: James Watts
Employer Name: Wattson Enterprises
Home Phone: (202) 374-4738
Work Phone: (301) 894-4789
Loan Estimation
Amount of Loan: 12500
Interest Rate(0 to 100): 10.25
Number of Months: 48
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-=- Car Loan Application -=-
-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Applicant Information
Full Name: James Watts
Employer Name: Wattson Enterprises
Home Phone: (202) 374-4738
Work Phone: (301) 894-4789
Loan Estimation
Loan Amount: $12,500.00
Interest Rate: 10.25 %
Number of Months: 48.00
Monthly Payment: $315.84
Press any key to continue...
File Initialization
The FileInfo class is equipped with one constructor whose syntax is:
public FileInfo(string fileName);
This constructor takes as argument the name of a file or its complete path. If you
provide only the name of the file, the compiler would consider the same directory of its
project. Here is an example:
FileInfo fleMembers = new FileInfo("First.txt");
Alternatively, if you want, you can provide any valid directory you have access to. In this
case, you should provide the complete path.
File Creation
The FileInfo constructor is mostly meant only to indicate that you want to use a file,
whether it exists already or it would be created. Based on this, if you execute an
application that has only a FileInfo object created using the constructor as done
above, nothing would happen.
This method simply creates an empty file. Here is an example of calling it:
using System;
using System.IO;
return 0;
}
}
The FileInfo.Create() method returns a FileStream object. You can use this
returned value to write any type of value into the file, including text. If you want to
create a file that contains text, an alternative is to call the FileInfo.CreateText()
method. Its syntax is:
public StreamWriter CreateText();
This method directly returns a StreamWriter object. You can use this returned object
to write text to the file.
File Existence
if (fleMembers.Exists == true)
return 0;
else
fleMembers.Create();
C# 3.0 Practical Learning 880
return 0;
}
}
Writing to a File
To write normal text to a file, you can first call the FileInfo.CreateText() method.
This method returns a StreamWriter object. The StreamWriter class is based on the
TextWriter class that is equipped with the Write() and the WriteLine() methods
used to write values to a file. The Write() method writes text on a line and keeps the
caret on the same line. The WriteLine() method writes a line of text and moves the
caret to the next line.
After writing to a file, you should close the StreamWriter object to free the resources it
was using during its operation(s).
1. To allow the user to create a new employee, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace WattsALoan2
{
class Program
{
private static void CreateNewEmployee()
{
string employeeNumber, employeeName;
FileInfo fleEmployees = new FileInfo("Employees.txt");
StreamWriter swrEmployees = fleEmployees.CreateText();
try
{
Console.WriteLine("Hiring New Employee");
Console.Write("Enter Employee Number as 00-000: ");
employeeNumber = Console.ReadLine();
Console.Write("Enter Employee Name: ");
employeeName = Console.ReadLine();
swrEmployees.WriteLine(employeeNumber);
swrEmployees.WriteLine(employeeName);
}
finally
C# 3.0 Practical Learning 881
{
swrEmployees.Flush();
swrEmployees.Close();
}
}
if (answer == 1)
CreateNewEmployee();
}
catch (FormatException)
{
Console.WriteLine("That was an invalid answer!\n");
}
. . . No Change
return 0;
}
}
}
Appending to a File
You may have created a text-based file and written to it. If you open such a file and find
out that a piece of information is missing, you can add that information to the end of the
file. To do this, you can call the FileInfo.AppenText() method. Its syntax is:
public StreamWriter AppendText();
When calling this method, you can retrieve the StreamWriter object that it returns,
then use that object to add new information to the file.
namespace WattsALoan2
{
public class Program
{
private static void CreateNewEmployee()
{
string employeeNumber, employeeName;
FileInfo fleEmployees = new FileInfo("Employees.txt");
StreamWriter swrEmployees = null;
try
{
Console.WriteLine("Hiring New Employee");
Console.Write("Enter Employee Number as 00-000: ");
employeeNumber = Console.ReadLine();
Console.Write("Enter Employee Name: ");
employeeName = Console.ReadLine();
swrEmployees.WriteLine(employeeNumber);
swrEmployees.WriteLine(employeeName);
}
finally
{
swrEmployees.Flush();
swrEmployees.Close();
}
}
Opening a File
As opposed to creating a file, probably the second most regular operation performed on
a file consists of opening it to read or explore its contents. To support opening a file,
the FileInfo class is equipped with the Open() method that is overloaded with three
versions.
If you have a text-based file and want to directly read from it, you can use the
StreamReader class that is equipped with the Read() and the ReadLine() methods. As
done for the StreamWriter class, after using a StreamReader object, make sure you
close it.
Deleting a File
If you have an existing file you don't need anymore, you can delete it. This operation
can be performed by calling the FileInfo.Delete() method. Its syntax is:
public override void Delete();
Here is an example:
using System;
using System.IO;
if (fleMembers.Exists == true)
fleMembers.Delete();
return 0;
}
}
Copying a File
C# 3.0 Practical Learning 885
You can make a copy of a file from one directory to another. To do this, you can call the
FileInfo.CopyTo() method that is overloaded with two versions. The first version has
the following syntax:
public FileInfo CopyTo(string destFileName);
When calling this method, specify the path or directory that will be the destination of the
copied file. Here is an example:
using System;
using System.IO;
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
if (fleMembers.Exists == true)
fleMembers.CopyTo(string.Concat(strMyDocuments,
"\\Federal.txt"));
return 0;
}
}
In this example, a file named Reality.txt in the directory of the project would be
retrieved and its content would be applied to a new file named Federal.txt created in the
My Documents folder of the current user.
When calling the first version of the FileInfo.CopyTo() method, if the file exists
already, the operation would not continue and you would simply receive a message box.
If you insist, you can overwrite the target file. To do this, you can use the second
version of this method. Its syntax is:
public FileInfo CopyTo(string destFileName, bool overwrite);
The first argument is the same as that of the first version of the method. The second
argument specifies what action to take if the file exists already in the target directory. If
you want to overwrite it, pass the argument as true; otherwise, pass it as false.
Moving a File
If you copy a file from one directory to another, you would have two copies of the same
file or the same contents in two files. Instead of copying, if you want, you can simply
move the file from one directory to another. This operation can be performed by calling
the FileInfo.MoveTo() method. Its syntax is:
public void MoveTo(string destFileName);
The argument to this method is the same as that of the CopyTo() method. After
executing this method, the FileInfo object would be moved to the destFileName path.
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
if (fleMembers.Exists == true)
fleMembers.MoveTo(string.Concat(strMyDocuments,
"\\Federal.txt"));
return 0;
}
}
Characteristics of a File
To keep track of it, after a file has been created, the operating system makes a note of
the date and the time the file was created. This information can be valuable in other
operations such as search routines. You too are allowed to change this date and time
values to those you prefer.
As mentioned already, the OS makes sure to keep track of the date and time a file was
created. To find out what those date and time values are, you can access the
FileSystemInfo.CreationTime property. This would be done as follows:
using System;
using System.IO;
if (SomeFile.Exists == true)
Console.WriteLine("Date and Time Created: " +
dteCreationTime.ToString());
return 0;
}
}
Many applications allow a user to open an existing file and to modify it. When people
work in a team or when a particular file is regularly opened, at one particular time, you
may want to know the date and time that the file was last accessed. To get this
information, you can access the FileSystemInfo.LastAccessTime property.
If you are interested to know the last date and time a file was modified, you can get the
value of its FileSystemInfo.LastWriteTime property.
The operating system requires that each file have a name. In fact, the name must be
specified when creating a file. This allows the OS to catalogue the computer files. This
also allows you to locate or identify a particular file you need.
When reviewing or opening a file, to get its name, the FileInfo class is equipped with
the Name property. Here is an example:
using System;
using System.IO;
if (SomeFile.Exists == true)
Console.WriteLine("The name of this file is: \"" +
SomeFile.Name + "\"");
return 0;
}
}
With the advent of Windows 95 and later, the user doesn't have to specify the extension
of a file when creating it. Because of the type of confusion that this can lead to, most
applications assist the user with this detail. Some applications allow the user to choose
among various extensions. For example, using Notepad, a user can open a text, a PHP,
a script, or an HTML file.
if (SomeFile.Exists == true)
Console.WriteLine("File Extension: " + SomeFile.Extension);
return 0;
}
}
One of the routine operations the operating system performs consists of calculating the
sizes of files it holds. This information is provided in terms of bits, kilobits, or kilobytes.
To get the size of a file, the FileInfo class is quipped with the Length property. Here
is an example of accessing it:
using System;
using System.IO;
if (SomeFile.Exists == true)
Console.WriteLine("File Size: " +
SomeFile.Length.ToString());
return 0;
}
}
Besides the FileInfo.Directoryname, to know the full path to a file, you can access
its FileSystemInfo.FullName property.
Attributes are characteristics that apply to a file, defining what can be done or must be
disallowed on it. The Attributes are primarily defined by, and in, the operating system,
mostly when a file is created. When the user accesses or opens a file, to get its
attributes, you can access the value of its FileSystemInfo.Attributes property. This
property produces a FileAttributes object.
When you create or access a file, you can specify or change some of the attributes. To
do this, you can a FileAttributes object and assign it to the
FileSystemInfo.Attributes property.
Directories
Introduction
A file can be moved from one directory to another. This operation is not possible
vice-versa since a file cannot contain a directory
A directory or a file can be created. One of the restrictions is that two files cannot
have the same name inside of the same directory. Two directories cannot have the
same name inside of the same parent directory.
A directory or a file can be deleted. If a directory is deleted, its files are deleted also
A directory or a file can be copied. A file can be copied from one directory to
another. If a directory is copied to a new location, all of its files are also copied to
the new location
namespace GeorgetownCleaningServices6
{
public class Customer
{
public string Name;
public string PhoneNumber;
}
}
5. To create a new class, on the main menu, click Project -> Add Class...
namespace GeorgetownCleaningServices6
{
public sealed class CleaningOrderDetails
{
// The date the cleaning items were deposited
public DateTime OrderDate;
public DateTime OrderTime;
// Numbers to represent cleaning items
public uint NumberOfShirts;
public uint NumberOfPants;
public uint NumberOtherItems;
8. To save the project, on the Standard toolbar, click the Save All button
Directory Creation
Before using a directory, you must first have it. You can use an existing directory if the
operating system or someone else had already created one. You can also create a new
directory. Directories are created and managed by various classes but the fundamental
class is Directory. Directory is a static class, which means all of its methods are
static, which means you will never need to declare an instance of the Directory class in
order to use it.
Besides the Directory class, additional operations of folders and sub-folders can be
performed using the DirectoryInfo class.
To create a directory, you can call the CreateDirectory() method of the Directory
class. This method is available in two versions. One of the versions uses the following
syntax:
public static DirectoryInfo CreateDirectry(string path);
This method takes as argument the (complete) path of the desired directory. Here is an
example:
E:\Programs\Business Orders\Customer Information
2. If the drive (in this case E) exists, the compiler moves to the first directory part of
the path; in this case this would be the Programs folder in the E drive.
If the folder doesn't exist, the compiler would create it. If that first director doesn't
exist, this means that the other directory(ies), if any, under the first don't exist. So,
the compiler would create it/them
C# 3.0 Practical Learning 892
3. If the first directory exists and if there is no other directory under that directory,
the compiler would stop and would not do anything further.
4. If the directory exists and there is a sub-directory specified under it, the compiler
would check the existence of that directory.
If the sub-directory exists, the compiler would not do anything further and would
stop.
If the sub-directory doesn't exist, the compiler would create it
5. The compiler would repeat step 4 until the end of the specified path
Before using or creating a directory, you can first check if it exists. This is because, if a
directory already exists in the location where you want to create it, you would be
prevented from creating one with the same name. In the same way, if you just decide to
directly use a directory that doesn't exist, the operation you want to perform may fail
because the directory would not be found.
Before using or creating a directory, to first check whether it exists or not, you can call
the Directory.Exists() Boolean method. Its syntax is:
public static bool Exists(string path);
This method receives the (complete) path of the directory. If the path exists, the
method returns true. If the directory doesn't exist, the method returns false.
To create a directory, you can call the CreateDirectory() method of the Directory
class.
Locating a File
One of the most routine operations performed in a directory consists of looking for a file.
Both Microsoft Windows operating systems and the user's intuition have different ways
of addressing this issue. The .NET Framework also provides its own means of
performing this operation, through various techniques. You can start by checking the
sub-directories and files inside of a main directory.
To look for files in a directory, the DirectoryInfo class can assist you with its
GetFiles() method, which is overloaded with three versions.
namespace GeorgetownCleaningServices6
{
public abstract class CustomerOrder
{
public abstract void ProcessOrder();
public abstract void ShowReceipt();
}
public CleaningDeposit()
{
this.custInfo = new Customer();
this.depot = new CleaningOrderDetails();
}
if (File.Exists(strPath))
{
C# 3.0 Practical Learning 894
FileStream stmCustomer =
File.Open(strPath, FileMode.Open, FileAccess.Read);
BinaryReader bnrCustomer = new BinaryReader(stmCustomer);
custInfo.Name = bnrCustomer.ReadString();
custInfo.PhoneNumber = bnrCustomer.ReadString();
Console.WriteLine("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=-");
Console.WriteLine("-/- Georgetown Cleaning Services
-/-");
Console.WriteLine("------------------------------------");
Console.WriteLine("Customer Name: {0}", custInfo.Name);
Console.WriteLine("Phone Number: {0}",
custInfo.PhoneNumber);
Console.WriteLine("------------------------------------\n");
}
else // If the customer information was not found in a file
{
Console.WriteLine("It looks like this is the first time
you " +
"are trusting us with your cleaning
order");
Directory.CreateDirectory(@"C:\Georgetown Cleaning Services\Customers");
FileStream stmCustomer = File.Create(strPath);
BinaryWriter bnwCustomer =
new BinaryWriter(stmCustomer);
Console.Write("Enter Customer Name: ");
strCustomerName = Console.ReadLine();
bnwCustomer.Write(strCustomerName);
bnwCustomer.Write(strPhoneFormatted);
custInfo.Name = strCustomerName;
custInfo.PhoneNumber = strTelephoneNumber;
}
return custInfo;
}
try
{
Console.Write("Enter the order date(mm/dd/yyyy): ");
this.depot.OrderDate =
DateTime.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("The value you entered is not a valid
date");
}
try
{
Console.Write("Enter the order time(hh:mm AM/PM): ");
C# 3.0 Practical Learning 895
this.depot.OrderTime =
DateTime.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine("The value you entered is not a valid
time");
}
this.ShowReceipt();
this.Save();
}
bnwCleaningOrder.Write(this.custInfo.Name);
bnwCleaningOrder.Write(this.custInfo.PhoneNumber);
bnwCleaningOrder.Write(this.depot.OrderDate.ToString());
bnwCleaningOrder.Write(this.depot.OrderTime.ToString());
bnwCleaningOrder.Write(this.depot.NumberOfShirts.ToString());
bnwCleaningOrder.Write(this.depot.NumberOfPants.ToString());
bnwCleaningOrder.Write(this.depot.NumberOtherItems.ToString());
bnwCleaningOrder.Write(this.depot.PriceOneShirt.ToString());
bnwCleaningOrder.Write(this.depot.PriceOtherItems.ToString());
bnwCleaningOrder.Write(this.depot.TaxRate.ToString());
bnwCleaningOrder.Write(this.depot.SubTotalShirts.ToString());
bnwCleaningOrder.Write(this.depot.SubTotalPants.ToString());
bnwCleaningOrder.Write(this.depot.SubTotalOtherItems.ToString());
bnwCleaningOrder.Write(this.depot.TotalOrder.ToString());
bnwCleaningOrder.Write(this.depot.TaxAmount.ToString());
bnwCleaningOrder.Write(this.depot.SalesTotal.ToString());
}
}
}
namespace GeorgetownCleaningServices6
{
public class CleaningRetrieval
{
private Customer custInfo;
private CleaningOrderDetails depot;
private string strPhoneNumber;
public CleaningRetrieval()
{
this.custInfo = new Customer();
this.depot = new CleaningOrderDetails();
}
DirectoryInfo di =
new DirectoryInfo(@"C:\Georgetown Cleaning Services\Cleaning
Orders");
FileInfo[] aryFiles = di.GetFiles("*",
SearchOption.AllDirectories);
if (found == true)
{
FileStream stmCleaningOrder =
File.Open(strFileFullname,
FileMode.Open,
FileAccess.Read);
BinaryReader bnrCleaningOrder = new
BinaryReader(stmCleaningOrder);
this.custInfo.Name = bnrCleaningOrder.ReadString();
this.custInfo.PhoneNumber =
bnrCleaningOrder.ReadString();
this.depot.OrderDate =
DateTime.Parse(bnrCleaningOrder.ReadString());
this.depot.OrderTime =
DateTime.Parse(bnrCleaningOrder.ReadString());
this.depot.NumberOfShirts =
uint.Parse(bnrCleaningOrder.ReadString());
this.depot.NumberOfPants =
uint.Parse(bnrCleaningOrder.ReadString());
this.depot.NumberOtherItems =
uint.Parse(bnrCleaningOrder.ReadString());
this.depot.PriceOneShirt =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.PriceAPairOfPants =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.PriceOtherItems =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.TaxRate =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.SubTotalShirts =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.SubTotalPants =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.SubTotalOtherItems =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.TotalOrder =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.TaxAmount =
decimal.Parse(bnrCleaningOrder.ReadString());
this.depot.SalesTotal =
decimal.Parse(bnrCleaningOrder.ReadString());
this.strPhoneNumber = "(" +
this.custInfo.PhoneNumber.Substring(0,
3) +
") " +
this.custInfo.PhoneNumber.Substring(3,
3) +
C# 3.0 Practical Learning 900
"-" +
this.custInfo.PhoneNumber.Substring(6,
4);
this.ShowReceipt();
}
else
Console.WriteLine("No cleaning order of " +
"that receipt number was found");
}
switch (answer)
{
case '1':
CleaningDeposit depotOrder = new CleaningDeposit();
depotOrder.ProcessOrder();
break;
case '2':
CleaningRetrieval previousOrder = new
CleaningRetrieval();
previousOrder.Open();
break;
default:
break;
}
Console.WriteLine();
}
}
}
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Arsene Cranston
Home Phone: 2021030443
Order Date: Monday, November 20, 2006
Order Time: 8:12 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 6 0.95 5.70
Pants 4 2.95 11.80
Other Items 2 4.55 9.10
------------------------------------
Total Order: $26.60
Tax Rate: 5.75 %
Tax Amount: $1.53
Net Price: $28.13
------------------------------------
Amount Tended: $30.00
Difference: $1.87
====================================
11.Remember the date you provided and close the DOS window
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Helene Craft
Home Phone: 3010221077
Order Date: Tuesday, November 21, 2006
Order Time: 9:25 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 3 0.95 2.85
Pants 0 2.95 0.00
Other Items 5 4.55 22.75
------------------------------------
Total Order: $25.60
Tax Rate: 5.75 %
Tax Amount: $1.47
Net Price: $27.07
------------------------------------
Amount Tended: $40.00
Difference: $12.93
====================================
13.Remember the date you provided and close the DOS window
14.Execute the application and choose to open an existing order. Here is an example:
Is this a new order or the customer is retrieving
items previously left for cleaning?
0. Quit
1. This is a new order
2. The customer is retrieving an existing order
Your Choice: 2
Enter Receipt Number: 11202006
====================================
-/- Georgetown Cleaning Services -/-
====================================
Customer: Arsene Cranston
Home Phone: 2021030443
Order Date: Monday, November 20, 2006
Order Time: 8:12 AM
------------------------------------
Item Type Qty Unit/Price Sub-Total
------------------------------------
Shirts 6 0.95 5.70
Pants 4 2.95 11.80
Other Items 2 4.55 9.10
------------------------------------
C# 3.0 Practical Learning 904
Total Order: $26.60
Tax Rate: 5.75 %
Tax Amount: $1.53
Net Price: $28.13
====================================
Introduction
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
{
static int Main(string[] args)
{
var Make = "Ford";
var Model = "Escort";
var Year = 1998;
var Color = 1;
try
{
bnwCar.Write(Make);
bnwCar.Write(Model);
bnwCar.Write(Year);
bnwCar.Write(Color);
}
finally
{
bnwCar.Close();
stmCar.Close();
}
return 0;
}
}
This is an example of the techniques we have used in previous lessons to save individual
data of primitive types:
C# 3.0 Practical Learning 906
The values can be retrieved with the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
try
{
Console.WriteLine("Make: {0}", bnrCar.ReadString());
Console.WriteLine("Model: {0}", bnrCar.ReadString());
Console.WriteLine("Year: {0}", bnrCar.ReadUInt32());
Console.Write("Color: ");
byte clr = bnrCar.ReadByte();
switch (clr)
{
case 1:
Console.WriteLine("Black");
break;
case 2:
Console.WriteLine("Gray");
break;
case 3:
Console.WriteLine("White");
break;
case 4:
Console.WriteLine("Red");
break;
case 5:
Console.WriteLine("Blue");
break;
}
}
finally
{
bnrCar.Close();
stmCar.Close();
}
return 0;
}
}
Here is an example:
using System;
using System.IO;
try
{
bnwCar.Write(vehicle.Model);
bnwCar.Write(vehicle.Year);
bnwCar.Write(vehicle.Color);
}
finally
{
bnwCar.Close();
stmCar.Close();
}
return 0;
When it comes to a class, the problem with saving individual fields is that you could
forget to save one of the fields. For example, considering a Car class, if you don't save
the Make information of a Car object and retrieve or open the saved object on another
computer, the receiving user would miss some information and the car cannot be
completely identifiable. An alternative is to save the whole Car object.
Object serialization consists of saving a whole object as one instead of its individual
fields:
In other words, a variable declared from a class can be saved to a stream and then the
saved object can be retrieved later or on another computer. The .NET Framework
supports two types of object serialization: binary and SOAP.
2. To save the project, on the Standard toolbar, click the Save All button
namespace GeorgetownCleaningServices7
{
public static class BusinessManagement
if (File.Exists(strPath))
{
Console.Write("\nEither the employee has already been
hired, ");
Console.WriteLine("or there is already another " +
"employee with that number.");
return;
}
else // If no employee with that number was found, create it
{
try
{
// If there is not yet a directory
// named Employees, then create it
Directory.CreateDirectory(@"C:\Georgetown Cleaning "
+
"Services\\Employees");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The folder could not be created");
}
try
{
fsEmployee = File.Create(strPath);
bwEmployee = new BinaryWriter(fsEmployee);
Console.Write("Enter Employee First Name: ");
string emplFName = Console.ReadLine();
Console.Write("Enter Employee Last Name: ");
string emplLName = Console.ReadLine();
Console.Write("Enter Hourly Salary: ");
double emplSalary = double.Parse(Console.ReadLine());
bwEmployee.Write(emplNumber);
bwEmployee.Write(emplFName);
bwEmployee.Write(emplLName);
bwEmployee.Write(emplSalary);
}
finally
{
C# 3.0 Practical Learning 910
bwEmployee.Close();
fsEmployee.Close();
}
}
Console.WriteLine();
}
}
}
namespace GeorgetownCleaningServices7
{
public static class Program
{
static int Main(string[] args)
{
var answer = '0';
do
{
try
{
Console.WriteLine("What do you want to do?");
Console.WriteLine("0. Quit");
Console.WriteLine("1. Hire a new employee");
Console.WriteLine("2. Process a payroll");
Console.Write("Your Choice: ");
answer = char.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Answer!");
}
switch (answer)
{
case '1':
BusinessManagement.HireEmployee();
break;
case '2':
break;
default:
break;
}
Console.WriteLine();
return 0;
}
}
}
Serialization
Binary serialization works by processing an object rather than streaming its individual
member variables. This means that, to use it, you define an object and initialize it, or
"fill" it, with the necessary values and any information you judge necessary. This creates
a "state" of the object. It is this state that you prepare to serialize. When you save the
object, it is converted into a stream.
To perform binary serialization, there are a few steps you must follow. When creating
the class whose objects would be serialized, start it with the [Serializable] attribute.
Here is an example:
[Serializable]
public class Car
{
C# 3.0 Practical Learning 912
public string Make;
public string Model;
public uint Year;
public byte Color;
}
The first argument to this method must be an object of a Stream-based class. In the
previous lessons, we saw how to create Stream objects (for example using the
FileStream class).
The second argument must be the object to serialize. This means that, before calling
this method, you should have built the object.
Here is an example:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Car
{
public string Make;
public string Model;
public uint Year;
public byte Color;
}
vehicle.Make = "Lexus";
vehicle.Model = "LS";
vehicle.Year = 2007;
vehicle.Color = 4;
bfmCar.Serialize(stmCar, vehicle);
return 0;
}
}
namespace GeorgetownCleaningServices7
{
[Serializable]
public class PayrollInformation
{
private string number;
private string fname;
private string lname;
private double salary;
private DateTime start;
namespace GeorgetownCleaningServices7
{
public static class BusinessManagement
{
public static void HireEmployee()
{
FileStream fsEmployee = null;
BinaryWriter bwEmployee = null;
if (File.Exists(strPath))
{
Console.Write("\nEither the employee has " +
"already been hired, ");
Console.WriteLine("or there is already another " +
"employee with that number.");
return;
}
// If no employee with that number
C# 3.0 Practical Learning 915
// was found, create it
else
{
try
{
// If there is not yet a directory named
// Employees, then create it
Directory.CreateDirectory(@"C:\Georgetown " +
@"Cleaning Services\Employees");
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("The folder could " +
"not be created");
}
try
{
fsEmployee = File.Create(strPath);
bwEmployee = new BinaryWriter(fsEmployee);
bwEmployee.Write(emplNumber);
bwEmployee.Write(emplFName);
bwEmployee.Write(emplLName);
bwEmployee.Write(emplSalary);
}
finally
{
bwEmployee.Close();
fsEmployee.Close();
}
}
Console.WriteLine();
}
PayrollInformation payroll =
new PayrollInformation();
if (!File.Exists(strEmployeePath))
{
Console.WriteLine("There is no employee with " +
"that number in our records");
return;
}
// If an employee with that number was found,
// continue with the payroll
else {
try
{
fsPayroll = new FileStream(strEmployeePath,
FileMode.Open,
FileAccess.Read);
brPayroll = new BinaryReader(fsPayroll);
payroll.EmployeeNumber = brPayroll.ReadString();
payroll.FirstName = brPayroll.ReadString();
payroll.LastName = brPayroll.ReadString();
payroll.HourlySalary = brPayroll.ReadDouble();
Console.WriteLine("\n------------------------" +
"------------------------");
Console.WriteLine("Employee #: {0}",
payroll.EmployeeNumber);
Console.WriteLine("Full Name: {0}, {1}",
payroll.FirstName,
payroll.LastName);
Console.WriteLine("Hourly Salary: {0:C}",
payroll.HourlySalary);
Console.WriteLine("-------------------------" +
"-----------------------\n");
}
finally
{
brPayroll.Close();
fsPayroll.Close();
}
payroll.StartPeriod = dteStartDate;
}
catch (FormatException)
{
Console.WriteLine("Invalid Date Entry");
}
}
payroll.Week2Monday = monday2;
payroll.Week2Tuesday = tuesday2;
payroll.Week2Wednesday = wednesday2;
payroll.Week2Thursday = thursday2;
payroll.Week2Friday = friday2;
payroll.RegularHours = regularHours;
payroll.OvertimeHours = overtimeHours;
payroll.RegularAmount = regularAmount;
payroll.OvertimeAmount = overtimeAmount;
payroll.TotalEarnings = totalEarnings;
ShowPayroll(payroll);
if (strAnswer.ToUpper() == "Y")
SavePayroll(payroll);
}
if (File.Exists(strPayrollFilename))
{
Console.WriteLine("The employee's payroll " +
"for that period exists already");
}
FileStream fsEmployeePayroll =
new FileStream(strPayrollFilename,
FileMode.Create);
BinaryFormatter bfEmployeePayroll =
new BinaryFormatter();
bfEmployeePayroll.Serialize(fsEmployeePayroll, pay);
fsEmployeePayroll.Close();
}
namespace GeorgetownCleaningServices7
{
public static class Program
{
static int Main(string[] args)
{
var answer = '0';
Console.WriteLine("========================" +
"========================");
Console.WriteLine("Georgetown Cleaning Services");
Console.WriteLine("========================" +
"========================");
do
{
try
{
Console.WriteLine("\nWhat do you want to do?");
Console.WriteLine("0. Quit");
Console.WriteLine("1. Hire a new employee");
Console.WriteLine("2. Process a payroll");
Console.WriteLine("3. View an employee's payroll");
Console.Write("Your Choice: ");
answer = char.Parse(Console.ReadLine());
Console.WriteLine();
}
catch (FormatException)
{
Console.WriteLine("Invalid Answer!");
}
switch (answer)
{
case '1':
BusinessManagement.HireEmployee();
break;
C# 3.0 Practical Learning 923
case '2':
BusinessManagement.CreatePayroll();
break;
case '3':
BusinessManagement.ViewPayroll();
break;
default:
break;
}
return 0;
}
}
}
------------------------------------------------
Employee #: 29-368
Full Name: Gertrude, Monay
Hourly Salary: $10.85
------------------------------------------------
8. Execute the application again and process another payroll. Here is an example:
================================================
Georgetown Cleaning Services
================================================
------------------------------------------------
Employee #: 86-025
Full Name: Anne, Harang
Hourly Salary: $7.50
------------------------------------------------
================================================
=$= Payroll summary =$=
------------------------------------------------
Employee #: 86-025
Full Name: Anne, Harang
Hourly Salary: $7.50
Start Period: Sunday, November 26, 2006
End Period: Saturday, December 09, 2006
------------------------------------------------
Monday Tuesday Wednesday Thursday Friday
Week 1: 8.00 6.50 8.50 8.00 8.00
Week 2: 9.00 8.50 8.00 9.50 8.00
------------------------------------------------
Monetary Summary
Hours Amount
Regular: 79.00 592.50
Overtime: 3.00 33.75
------------------------------------------------
Net Pay: 626.25
================================================
De-Serialization
Once the Deserialize() method has returned the desired object, you can access its
values. Here is an example:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Car
{
public string Make;
public string Model;
public uint Year;
public byte Color;
}
class Program
{
static int Main(string[] args)
{
var stmCar = new FileStream("Car3.car", FileMode.Open);
var bfmCar = new BinaryFormatter();
var vehicle = (Car)bfmCar.Deserialize(stmCar);
switch (clr)
{
case 1:
Console.WriteLine("Black");
break;
case 2:
Console.WriteLine("Gray");
break;
case 3:
Console.WriteLine("White");
break;
case 4:
Console.WriteLine("Red");
break;
case 5:
Console.WriteLine("Blue");
break;
}
stmCar.Close();
return 0;
}
}
C# 3.0 Practical Learning 927
Practical Learning: De-Serializing an Object
namespace GeorgetownCleaningServices7
{
public static class BusinessManagement
{
public static void HireEmployee()
{
. . . No Change
}
if (!File.Exists(strFilename))
{
Console.Write("There is no employee " +
"with that number.");
}
else
{
FileStream fsEmployee = null;
BinaryReader brEmployee = null;
try
{
(PayrollInformation)bfPayroll.Deserialize(fsPayroll);
ShowPayroll(pay);
}
}
}
C# 3.0 Practical Learning 929
public static void ShowPayroll(PayrollInformation payed)
{
. . . No Change
}
}
}
================================================
=$= Payroll summary =$=
------------------------------------------------
Employee #: 29-368
Full Name: Gertrude, Monay
Hourly Salary: $10.85
Start Period: Sunday, November 12, 2006
End Period: Saturday, November 25, 2006
------------------------------------------------
Monday Tuesday Wednesday Thursday Friday
Week 1: 8.00 8.50 9.50 8.00 8.50
Week 2: 6.50 7.00 8.00 6.00 7.00
------------------------------------------------
Monetary Summary
Hours Amount
Regular: 74.50 808.33
Overtime: 2.50 40.69
------------------------------------------------
Net Pay: 849.01
================================================
================================================
C# 3.0 Practical Learning 930
=$= Payroll summary =$=
------------------------------------------------
Employee #: 86-025
Full Name: Anne, Harang
Hourly Salary: $7.50
Start Period: Sunday, November 26, 2006
End Period: Saturday, December 09, 2006
------------------------------------------------
Monday Tuesday Wednesday Thursday Friday
Week 1: 8.00 6.50 8.50 8.00 8.00
Week 2: 9.00 8.50 8.00 9.50 8.00
------------------------------------------------
Monetary Summary
Hours Amount
Regular: 79.00 592.50
Overtime: 3.00 33.75
------------------------------------------------
Net Pay: 626.25
================================================
SOAP Serialization
Introduction
2. To create a new class, on the main menu, click Project -> Add Class
namespace PropertyRental1
{
public enum TypeOfProperty
{
Appartment,
SingleFamily,
Townhouse,
Unknown
}
[Serializable]
public class Property
{
private long propCode;
private TypeOfProperty tp;
private Condition cond;
private short beds;
private float baths;
private int levels;
private decimal val;
public Property()
{
Random rnd = new Random();
propCode = rnd.Next(100000, 999999);
tp = TypeOfProperty.Unknown;
cond = Condition.Unknown;
beds = 0;
baths = 0.0f;
levels = 0;
val = 0.00M;
}
}
}
5. To create a new class, on the main menu, click Project -> Add Class
namespace PropertyRental1
{
[Serializable]
public class PropertyListing
{
private Property[] prop = new Property[100];
8. Save all
When creating the class whose objects would be serialized, mark it with the
[Serializable] attribute. Here is an example:
[Serializable]
public class Car
{
public string Make;
public string Model;
public uint Year;
public byte Color;
}
To support SOAP serialization, the .NET Framework provides the SoapFormatter class.
This class is defined in the System.Runtime.Serialization.Formatters. Soap
namespace that is part of the System.Runtime.Serialization.Formatters.
Soap.dll assembly. In order to use The SoapFormatter class, you must reference this
assembly. Then, you can create an object and initialize it as you see fit. Before saving it,
as always, create a Stream-based object that would indicate the name (and location) of
the file and the type of action to perform. Then, declare a SoapFormatter variable
using its default constructor. To actually save the object, call the Serialize() method
of this class. This method uses the same syntax as that of the BinaryFormatter class:
it takes two arguments. The first is a Stream-based object. The second is the object that
needs to be serialized.
Here is an example:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
[Serializable]
public class Car
{
public string Make;
public string Model;
public uint Year;
public byte Color;
}
vehicle.Make = "Volvo";
vehicle.Model = "S40";
vehicle.Year = 2006;
vehicle.Color = 3;
var stmCar =
new FileStream("Car4.car",
FileMode.Create);
var sopCar = new SoapFormatter();
1. To add SOAP support to your project, on the main menu, click Project -> Add
Reference...
2. In the Add Reference dialog box and in the .NET tab, scroll down and select
System.Runtime.Serialization.Formatters.Soap:
3. Click OK
namespace PropertyRental1
{
class Program
{
static PropertyListing CreateListing()
{
Random rnd = new Random();
Property prop = new Property();
PropertyListing listing = new PropertyListing();
listing[i] = prop;
}
return listing;
}
FileStream prpStream =
new FileStream("properties.rnt",
FileMode.Create);
SoapFormatter prpSoap = new SoapFormatter();
prpSoap.Serialize(prpStream, props);
Console.WriteLine("{0}.----------------------------------", i + 1);
Console.WriteLine("Property #: {0}",
prop.PropertyCode);
Console.WriteLine("Type: {0}",
prop.PropertyType);
Console.WriteLine("Condition: {0}",
prop.PropertyCondition);
Console.WriteLine("Bedrooms: {0}", prop.Bedrooms);
Console.WriteLine("Bathrooms: {0}", prop.Bathrooms);
Console.WriteLine("Stories: {0}", prop.Stories);
Console.WriteLine("Market Value: {0}\n",
prop.MonthlyRent);
}
Console.WriteLine("======================================");
return 0;
}
}
}
[Serializable]
public class Car
{
public string Make;
public string Model;
public uint Year;
public byte Color;
}
Console.WriteLine("Car Information");
Console.WriteLine("Make: {0}", vehicle.Make );
Console.WriteLine("Model: {0}", vehicle.Model);
Console.WriteLine("Year: {0}", vehicle.Year);
Console.Write("Color: ");
switch (vehicle.Color)
{
case 1:
Console.WriteLine("Black");
break;
case 2:
Console.WriteLine("Gray");
break;
case 3:
Console.WriteLine("White");
break;
case 4:
Console.WriteLine("Red");
break;
case 5:
Console.WriteLine("Blue");
break;
}
return 0;
}
}
namespace PropertyRental1
{
class Program
{
static int Main()
{
Property prop = new Property();
return 0;
}
}
}
4. To apply an example of updating the file, change the contents of the Program.cs
file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;
// That's it
return 0;
}
}
}
Details on Serialization
Partial Serialization
In the examples we have used so far, we were saving the whole object. You can make it
possible to save only some parts of the class. When creating a class, you can specify
what fields would be serialized and which ones would not be. To specify that a member
cannot be saved, you can mark it with the [NonSerialized] attribute. Here is an
example:
[Serializable]
public class Car
{
public string Make;
public string Model;
After creating the class, you can declare a variable of it and serialize it, using either the
binary or the SOAP approach. Here is an example:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Car
{
public string Make;
public string Model;
vehicle.Make = "Lexus";
vehicle.Model = "LS";
vehicle.Year = 2007;
vehicle.Color = 4;
vehicle.Value = 28640M;
bfmCar.Serialize(stmCar, vehicle);
return 0;
}
}
You can then retrieve the object and its values, using any of the techniques we learned
earlier. Here is an example:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
public class Car
{
C# 3.0 Practical Learning 942
public string Make;
public string Model;
Console.WriteLine("Car Information");
Console.WriteLine("Make: {0}", vehicle.Make);
Console.WriteLine("Model: {0}", vehicle.Model);
Console.WriteLine("Year: {0}", vehicle.Year);
Console.Write("Color: ");
switch (vehicle.Color)
{
case 1:
Console.WriteLine("Black");
break;
case 2:
Console.WriteLine("Gray");
break;
case 3:
Console.WriteLine("White");
break;
case 4:
Console.WriteLine("Red");
break;
case 5:
Console.WriteLine("Blue");
break;
}
Console.WriteLine("Value: {0}\n", vehicle.Value);
return 0;
}
}
The .NET Framework is filled with many classes ready for serialization. To know that a
class is ready for serialization, when viewing its documentation either in the MSDN web
site or in the help documentation, check that it is marked with the
[SerializableAttribute]. Here is an example of such as class: