Basic C# Programming Study Guide - BCSM-16 V1.0 - Interactive
Basic C# Programming Study Guide - BCSM-16 V1.0 - Interactive
BCSM-16
Basic C# Programming
BCSM-16
Compiled by: Kyle Brunette, Angelique Kolle, Lance Whyte, Cedric Maenetja,
Daniel Sansom and Tatenda Tagutanazvo
Version 1.0
This module covers the basics of C# and, with due diligence and application to
understanding all the concepts discussed, each student should be able to
program in C# by the end of the module. There are many ideas and concepts
that will be of benefit to any programmer, no matter which programming
language is used in the future.
Resources
The study guide does not reference the textbook. The textbook
is an invaluable tool should difficulties be experienced at any
point in the module. The textbook and study guide are based on
the assumption that the concepts may be unfamiliar and
detailed explanations are always provided.
This course is divided into three units. Each unit consists of:
• Theory
• Examples
• Exercises
A theory examination will be written at the end of each unit. You will need to
complete a project at the end of this module (Unit 3). You will write a theory
and a practical examination after you have completed the project. Ensure that
you know and understand the theory before continuing with an exercise,
project or examination. Everyone wants to get their hands dirty as soon as
possible with regard to actual programming, but there will be many
opportunities to practise what you have learnt. Work through the examples in
the reference book (Microsoft Visual C# 2013 Step by Step) and complete all
the exercises in this study guide before attempting the project as well as the
examinations. Application questions will be asked in the examination – you
must be able to apply your knowledge to practical situations.
You will not pass the examination if you rush through the material and do the
project without understanding what you have learnt. The examinations are
designed to test theory, insight and practical skills. Theory examinations will
consist of true/false questions, multiple choice questions, identifying errors in
an existing section of code, multiple response questions and selection
questions. The practical examination will present you with the opportunity to
code a program on a computer.
It is very important to use all the study aids available to you. Some of the
questions in the examinations will test your general knowledge on advanced
subjects that may not have been covered in the study guide, although the
content in the study guide will be sufficient to ensure that you pass each unit.
Take note that each unit builds on previous units. Examinations will cover all
the material with which you should be familiar. For example, the examination
at the end of Unit 3 will also cover material from Units 1 and 2.
You have a certain number of days to complete the course, including all three
units, the project, the theory examinations and the practical examination.
All the units follow the same structure. You will be presented with the
outcomes for each unit. These outcomes can be used as an indication of what
is important and what you should focus on when going through the unit’s
material. Notes will follow this. Read these sections carefully. Key terms will
list what you should have read and understood in the unit.
You will be presented with exercises that will require you to apply your
knowledge of the material. Ensure that you understand the exercises. Ask for
help if you are unsure of what to do. Revision questions will give you an
indication of what to expect in the examination, although you should not rely
on these questions as your only reference. Some examination questions will
undoubtedly be more difficult than the revision questions.
You will find the project specifications at the end of the study guide. Please
do not start working on the project until you have completed (and understood)
all the exercises. Once you have covered all the topics from the previous units
and you are satisfied that you have met the outcomes, you may start the
project. Use the project specifications as a guide. They will list everything that
you need to do to comply with the project’s requirements. If your project does
not comply with these requirements, it will not be marked. Please see the
mark sheets for each project. These indicate how the marks will be allocated.
It is suggested that you read through your project as soon as you receive your
new study guide. This will give you an idea of what is expected of your project.
As you progress through the guide, you will start identifying how to approach
the project. You should only start working on your project once you have a
good understanding of the material. Performing the following steps will help to
ensure that you complete your project successfully:
1. Read the relevant section in the study guide to familiarise yourself with
the material.
2. Type the examples. This might seem pointless, but it is an easy way to
familiarise yourself with the language. Experiment with the code; make
deliberate mistakes to get a feel for the way in which the compiler
handles errors.
3. Complete the exercises at the end of every chapter in the reference book
(Dorman, S. 2010. Sams teach yourself Visual C# 2010 in 24 hours).
The best way to learn a language is to practise it. This will also help you
in the examination.
4. Only start with the project if you feel comfortable with the material.
5. Make use of textbooks when the need arises.
If these guidelines are followed, the projects may not prove too difficult.
Your lecturer will mark your projects and you will find the project evaluation
forms at the back of your study guide. Your lecturer can also provide these to
you on request. The general expectations for each of the sections are provided
below:
Project specification
The project specification provides a detailed description of what the project
requires and how the project must function. This specification must be
printed and included with your final project submission. This includes any
projects submitted electronically
Program design
You must follow the project specifications. For example, if the project
specifications instruct you to use a specific class, you will need to use that
class. You will be allowed to be creative, but you will be required to
incorporate certain elements into the project.
Source code
For any serious program that you develop, it is almost guaranteed that
either you or another programmer will have to return to the code on
occasion to correct a problem or add a new feature. It is thus important
that your code is easy to read. One way to make code easy to read is by
using indentation and white space.
Your code should also contain comments that clearly explain what is
intended by structures and blocks in the code. If a programmer who has
to maintain the code has to try to understand what it was that you
intended first, it not only wastes time but also opens the possibility that
the intention may be misunderstood, which may lead to further problems.
For example:
• User interface
o Ensure that the screen layout is pleasing to the eye.
o Always provide the user with clear instructions (including messages
like ‘Press any key to continue...’ when you are waiting for the user to
read the screen and ‘Please wait a moment’ when the program will be
delayed for a few seconds).
o Display money values with an appropriate symbol (e.g. R, £ or $) and
percentages with the percentage symbol (%).
o Make use of input validation to ensure that the correct data has been
entered by the user. If incorrect data has been entered, present a
user-friendly message to the user that indicates this.
• User documentation
All programs should be adequately documented:
o Those who have to maintain the code must know what was intended
by every single line of code (called program design documentation and
source code documentation).
o Those who have to use the program must know how to run it, what to
expect and what output will be displayed or printed (called user
documentation).
o You should supply extensive descriptions for your classes and
members.
o Documentation must be in the form of a Word document unless stated
otherwise.
o The user documentation must adequately explain how to install and
run the application, working on the assumption that the end user has
no prior experience of doing so.
• Project documentation
Your project documentation must include all of the following when
submitting your project:
o Project specification
o Program design
o Project source code
o User documentation
o Databases (if any)
o Resources (if any)
o System requirements (if any)
o Rough work (if any)
• System requirements
o Dual Core Processor
o Microsoft Windows 7
o 2 GB RAM
o 5 GB of available disk space
o Microsoft Visual Studio 2013 Professional
A pass is awarded for the unit on the achievement of all the pass assessment
criteria.
This unit counts 10% towards part A of the C# mark, and there are 12 days in
which to complete it. The time and marks are scheduled as follows:
Reading 10 days
Exam preparation and exam 2 days 10%
When a C# application is compiled, the compiler converts the source code from
regular C# to another language, known as the Common Intermediate
Language (CIL). This is then stored in an executable file (with the .exe
extension) which can be run using the .NET virtual machine. When the
executable file is run, the .NET Framework uses JIT compilation to convert
the application into machine code which can in turn be run by the operating
system.
An IDE is an application that is used to write code and create applications. The
standard IDE allows applications to be tested and run, as well as incorporating
other features such as syntax highlighting and code completion. The Visual
Studio IDE has all these features and more.
Use the DVD provided with this guide and select vs_professional.exe from the
auto-run menu. The installer screen, as shown in Figure 2, will be displayed.
This is the Start Page of Visual Studio Professional, which will be displayed
every time the IDE is run. The Start Page has several features, such as
Announcements which provides updates on the Visual Studio developments.
The list of ‘Recent’ displays a list of projects that have been worked on
recently. Clicking a project in this list will open the selected project for editing.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace greetingApplication
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 string userName;
14
15 Console.Write("Please enter your name : ");
16 userName = Console.ReadLine();
17
18 Console.WriteLine("Greetings, " + userName);
19 Console.ReadLine();
20 }
21 }
22 }
Line 1-5: A program can have multiple using statements to include different
namespaces.
Line 9: This line contains the class declaration. A class defines attributes and
behaviours. Each namespace can have more than one class.
Line 11: The Main method is the entry/starting point of each C# program and
contains the code that will run first when the class is executed. Without the
Main method the program cannot run and a class cannot contain more than
one Main method.
Line 13: A variable named userName of the string data type is declared.
Line 15: Write is a method of the Console class that can be found in the
System namespace and will display the message ‘Please enter your name:’ on
the console.
Line 16: Readline is a method of the Console class that reads user input from
the console. When the user enters their name and presses enter the value will
be assigned to the username variable.
Line 19: Adding Console.ReadLine() at the end of the code in the Main method
prevents the console from closing too quickly when the program runs.
Press <F5>, or open the DEBUG menu and click Start Debugging.
1.2.1.1 Classes
A class is one of the most important concepts of object-oriented programming.
A class is best thought of as a template from which objects are created. The
template describes what attributes and behaviours the object will have. For
example, a Book class does not refer to a specific book, but rather the general
description of a book. The class will never have specific information about any
book.
1.2.1.2 Objects
An object is a specific instance of a class. Where the Book class describes a
book, the instance is an actual book. For example Twilight, Fallen, etc. are
instances of the Book class.
1.2.1.3 Attributes
An attribute is a piece of information about an object. For example, a book
might have a name, an author and an ISBN number. In programming terms,
attributes are often referred to as instance variables, where an instance is
the object created from the class.
1.2.1.4 Behaviours
A behaviour is something that an object does. A book can be read, printed,
bought or sold. A method to count the number of pages, words, or lines in the
book could be developed. Behaviours can also cover things that a class will
automatically do. These are known as events. Note, however, that an event
does not have any code in itself, but rather that the event calls a specific
method called the event-handler.
Four main principles are common to all OOP languages, namely: abstraction,
encapsulation, inheritance and polymorphism.
1.2.2.1 Abstraction
An abstraction is an idea or concept that is not associated with one specific
object. In programming languages, abstract templates (classes) that store the
essential attributes and behaviours for a type of object are created. For
example, an abstract Vehicle class would define all the attributes and
behaviours common to all vehicles. Because the Vehicle class is abstract, it
would not be possible to create objects from it – it can be considered as a
template from which other classes can be created through inheritance (which
can then be used to create objects).
1.2.2.2 Encapsulation
Encapsulation, also known as data-hiding, is a principle of object-oriented
programming which states that all the attributes and behaviours of an object
should be grouped together in one data type or class. What this ultimately
means is that each class should be as self-sufficient as possible. The main
reason for this is to hide the implementation of the attributes and/or
behaviours of a class from other classes. The class thus presents a standard,
constant interface.
For example, the Drive()method is called to enable the Vehicle class to move.
However, it is not necessary to know how the Drive()method actually works,
only what it is intended to do. This allows programmers to change how their
classes work (which may be necessary at some point) without breaking
compatibility with other classes. In other words, other classes that use the
Vehicle class would not need to be modified to continue to work as before.
1.2.2.3 Inheritance
Inheritance is a core principle of object-oriented programming which allows
one class to inherit all the attributes and behaviours of another class. This
allows a class to be specialised by inheriting from it and providing additional
functionality (attributes and behaviours). For example, when a new Car class is
created from the abstract Vehicle class, it has not only its own unique
functionality, but also has all the functionality inherited from the Vehicle class.
Likewise, a Truck class and a Bike class will also inherit the functionality from
the Vehicle class, much like the Car class, but the additional functionality
provided will be different. These relationships are illustrated in Figure 7.
Drive
Park
LoadPassenger LoadCargo
1.2.2.4 Polymorphism
Polymorphism literally means ‘many forms’. In object-oriented programming,
the principle of polymorphism allows behaviours inherited from a parent class
to be overridden so that the derived class (the class that inherits from the
parent) has behaviours that work differently from the parent class, although
they share the same name. For example, the Car and Bike classes might both
inherit a method called Drive(), but each would implement it differently.
In practical terms, there could be an array of Vehicle objects, any one of which
could be a Car, Bike or Truck. It might not be known what Vehicle type it is,
nor would it be necessary to know. When the Drive()method is called, the
program automatically calls the method in the derived class. If no method of
that name existed in the derived class, the program will then look for one in
the parent class, and so on.
1.3.1 Comments
/*
* This is a
* multi-line
* comment
*/
Figure 10 – C# multi-line comment
All coding should always be documented with comments that briefly explain
what the program is doing. Comments can also be used to comment-out
problematic sections of code to allow the program to compile, or to include or
hide, code used for debugging purposes.
Unsigned int, short and long data types can be uint x =1;
data unsigned, i.e. only positive if you place ushort y = 2;
types a u in front of their declaration. ufloat z = 1.4;
Figure 12 shows how to declare a variable and assign an initial (starting) value
to it.
{
int x = 10;
}
NOTE It is possible to declare two variables with the same name if one of
them is declared at the top of the program and the other is declared
within a method. The one declared within the method will be used
within the method, and the other one will be used everywhere else.
They are not the same variable.
A control statement is any statement that can change the flow of the program
depending on certain conditions. Usually, a variable will be checked against
some predefined value to determine what the program should do next.
1.3.3.1 Conditions
A condition is a statement that is checked by a control statement to determine
whether it is true or not. For example, the condition:
Table 2 lists the conditional operators. These conditional operators make the
most sense when used to compare numerical variables, but it note that they
can often be used for other data types.
In this example, the compound condition would evaluate to true only if:
In any other circumstance, it would evaluate to false. Note the use of the
brackets.
The compound condition operators are shown in Table 3.
if (condition)
{
// Statements.
} // If code block ends here.
string stringResult = 2 < 1 ? "2 is smaller than one" : "2 is greater than one";
Console.WriteLine(stringResult);
Console.ReadLine();
Because the condition used by the ternary operator is false in the above
example, the print out is: 2 is greater than one.
Multiple else if statements may be used as part of one chain, but there may
only be one if statement and one else statement. The else if and else are
both completely optional – removing them both would revert the statement to
a basic if statement.
if (condition)
{
// Statements
} // if code block ends here
else if (condition)
{
// Statements
} // else … if code block ends here
else if (condition)
{
// Statements
} // else … if code block ends here
else
{
// Statements
} // else code block ends here
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Operators
{
class Conditions
{
static void Main(string[] args)
{
int scoreTeam1 = 3;
}
}
switch (variable)
{
case 0:
// Code here is executed if 'variable' == 0
break;
case 1:
// Code here is executed if 'variable' == 1
break;
default:
// Code here is executed if none of the above ‘cases’ are true
break;
} // end of switch statement
Example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Statements
{
class CaseStament
{
static void Main(string[] args)
{
char grade = 'A';
switch (grade)
case 'B':
case 'C':
Console.WriteLine("Well done");
break;
case 'D':
case 'E':
Console.WriteLine("You passed");
break;
case 'F':
Console.WriteLine("Oops! You failed. Better luck next
time...");
break;
default:
Console.WriteLine("Invalid code!");
break;
}
Console.ReadLine();
}
}
}
1.3.3.7 Loops
A loop is a special kind of control statement, which can execute the code within
its code block multiple times depending on certain conditions.
Initialisation statement:
This statement is executed when the for loop starts. It is intended to be
used to declare a variable that will be used to count the number of times
the loop has executed, as well as assign an initial value to that variable. In
Test condition:
This is a Boolean condition which will be tested every time the loop
executes. If the condition evaluates to false, the loop will terminate and
the program will continue executing the code after the for loop. In this
example, the for loop will continue to execute so long as the loopCounter
variable is smaller than, but not equal to, 5.
Counting expression:
This is a statement that is intended to increment (increase) or
decrement (decrease) the loop variable. In this example, loopCounter is
increased by 1 every time the for loop executes. The counting expression
does not necessarily have to modify the loop variable; it could also modify
anything else. Be careful to ensure that at some point the values which
must be evaluated by the test condition change so that the test condition
evaluates to false, or the loop will repeat infinitely, i.e. it will never end
and the program will never continue. This is known as an infinite loop and
should be avoided in almost all situations.
while (condition)
{
// Code to be executed.
} // End of while loop.
Before the first execution, and for every execution thereafter, a while loop
checks the condition before executing the code within the while block. If the
condition evaluates to false, the loop will terminate and the program will
continue executing code after the while loop. If the condition is false before the
first execution, the program will continue execution after the while loop
without executing the loop code. As in the case of a for loop, take care not to
create infinite loops.
do
{
// Code to be executed.
}
while(condition)
int messageToHide = 3;
for(int loop = 0; loop < 10; loop = loop + 1)
{
if(loop == messageToHide)
{
continue;
}
However, if the value of loop is equal to the value of messageToHide, then the
continue statement is executed, and the rest of the loop is skipped, the
counting expression is executed, and the loop begins again. From a user
perspective, 9 messages will be seen, one after the other, for each execution
of the loop except for the fourth execution (when loop == 3).
Note that the unary plus operator serves no true function. In mathematics,
placing a plus sign before a number does not change the value of that number
in any way. The unary minus will change a positive number to a negative one,
or a negative number to a positive one.
int number;
// These two statements mean exactly the same thing.
number = 5;
number = +5;
There are many other unary operators, and these are listed in Table 4.
// The operators can also be used without assigning the return value to
another // variable.
num1++; // num1’s value is increased by one.
As with conditional operators, binary operators usually make the most sense
when working with numerical variables. However, some can be used with other
variable types. For example, strings may be concatenated (appended one to
the other) using the binary plus operator. This has already been seen in action
in the output (Console.WriteLine("")) of some of the examples.
int num1 = 9;
int num2 = 4;
num1 = num1 + num2++;
1.4.1 Arrays
An array is a special type of variable that can hold zero or more values within
it. An array can be of any type, but all its elements (values stored within it)
must be of the same base type. The following is an example of a basic
application that uses an array (this code would be found inside the Main
method):
The above example declares a string array with 5 elements, and sets the value
for each of those elements. A for loop is used to iterate through the array and
display each element.
The number between the square brackets in the initialisation statement (right-
hand side) indicates how many elements the array should have. Once
declared, this size cannot be changed.
It is also possible to declare an array with initial values. The following code
shows how this can be done:
Setting the value of an array element is thus much the same as for a normal
variable.
Console.WriteLine(customers[0]);
Notice that the number 0 is used with the index operator to retrieve the first
element.
This is all very well for situations where the exact element(s) of the array are
known, but in many situations this may very well not be known beforehand.
For these and similar situations (which is in most situations where arrays are
involved), a variable is used to specify which element of the array to retrieve.
In the following example, a for loop is used to retrieve each element of the
array and display its value. This is where the true value of loops and arrays
becomes evident; the same operations on or with every element in an array is
To adjust the loop to iterate through an entire array without knowing its exact
size, the test condition of the for loop is simply modified. All arrays have a
property called Length which can be used to retrieve the size of the array. The
updated loop looks as follows:
NOTE Always make sure that the element you are attempting to access
exists (i.e. a value has been set at the specified index, and that the
index of the element is not greater than the size of the array. Also
always ensure that your array index is not negative.) Failing to do
so will lead to an exception being thrown.
Numerical values of type short, int, float, decimal, and so on, are assigned
the value zero.
Values of type char are assigned the Unicode character \u0000 (Null).
Values of type bool are initialised to the value false.
Values of reference types are initialised to null.
To test the methods, enter the code into the Main method in a new
application.
// Declare variable.
string testString = "This is a test string";
// Pause.
Console.ReadLine();
1. Pi is equal to 3.14285714285714.
2. Pi is equal to 3.14.
3. Pi is equal to 3.14E+000
4. Pi is equal to 3.14 twice that is 6.29.
5. 3.14, 6.29, 9.43, 12.57
It is often necessary to convert data from one data type into another. For
example, input is almost always read in as a string value. Mathematical
operations cannot be performed with a string. In this case, the string value will
have to be converted into an integer value.
// Variable declaration.
int userAge;
// Pause.
Console.ReadLine();
On this line, a string is read in from the user, via the console. That string is
then parsed into an integer and assigned to the integer variable userAge.
Strings may be parsed into other data types as well. For example, the
following code converts a string into the double data type:
// Age is an int.
Console.WriteLine("Age : " + age);
int radius = 5;
double circumference = 3.14 * 2 * radius;
The two integer values (2 and radius) are first implicitly converted to the
double data type before the calculation is performed.
double d = 3.14;
int i = (int)d * 2;
1.4.4 Enumeration
Console.ReadLine();
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vehicleTracking
{
class Program
{
static void Main(string[] args)
{
}
}
}
This code shows the layout of a basic class called Program. The code will now
be studied in detail.
using System;
This is a using statement. It imports the code from another namespace (in
this case, the System namespace) into the application so that it may be used
without having to specify the full path name. This will be discussed in greater
detail later on.
namespace vehicleTracking
This is a namespace declaration. This declares that all the code between its
opening and closing brackets is part of the vehicleTracking namespace.
class Program
Notice how the new class generated by the IDE is very similar to the Program
class, except that there are no method declarations.
Vehicle
Make
Model
Condition
Price
Note that the class diagram does not show any method declarations. This is
because none are needed; the Vehicle class is only going to be used to store
information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vehicleTracking
{
class Vehicle
{
// Variable declaration.
public string make = "";
public string model = "";
public int condition = 0;
public double price = 0;
}
}
The code declares the four variables shown in the class diagram. The reason
that there is a public keyword before each of them is that these variables need
to be accessible outside of the class. There are other access modifier
keywords, but these will be discussed in detail later on in the guide.
// Empty constructor.
public Vehicle()
{
}
// Constructor.
public Vehicle(string newMake, string newModel, int newCondition, double
newPrice)
{
Make = newMake;
Model = newModel;
Condition = newCondition;
Price = newPrice;
}
Note that two constructors have been created above: one empty constructor,
and one that takes parameters. The basic Vehicle class is now complete.
Objects will now be created from this class.
Type the following code inside the Main method of the Program class:
This code creates a new instance of the Vehicle class called testVehicle. The
testVehicle instance has its variables set by the constructor, using the values
passed to it in this line of code. In order to test this code out, another line of
code must be added.
Type the following code inside the Main method of the Program class, after the
previous line:
Console.ReadLine();
The above code displays all the variable values of the testVehicle in a format
that is easily understandable. The Console.ReadLine(); statement is used to
prevent the console window from closing after the program has finished its
execution.
#region MyRegion
#endregion
Replace the word MyRegion with the desired name for the region. In this
case, the first region will be called Properties.
Any code typed between the opening (#region) and the closing (#endregion)
tags will be part of that region. The primary advantage of a code region is the
option of whether or not to display the code in it, merely by clicking the small
minus (-) sign to the left of the region name.
1.5.4 Properties
In C#, a property is a special type of instance variable which can execute code
to calculate a return value or validate a set value (among other uses).
Convert each of the Vehicle instance variables into properties. This will allow
for more control over the values that those properties can accept and return.
Each of the following properties created should be placed inside the Properties
code region.
This property actually consists of two parts: the first being a private string
variable called mMake, and the second being a public string property called
Make. The get method of the Make property simply returns the value stored in
the mMake variable. Similarly, the set method takes the value it receives and
stores it in the mMake property. Note that in the set method the value
keyword represents the value to which the property has been set.
With this property, only the Vehicle class itself will have access to the mMake
variable as it is private. The property itself, however, is public and provides
access to the value through its get and set methods. This is part of the
encapsulation principle – the inner workings of the class are not directly
accessible.
Note that properties do not need to have both a get and a set property. Read-
only properties and write-only properties will only accept values.
Notice that the set method for the Price property ensures that no matter what
value is passed to it, the stored value is never less than zero.
The above code shows a very simple method which will display the text Hello!
on the screen when this method is called. Methods, such as this one, are used
to avoid repetitive code.
1.5.5.1 Parameters
Methods can also accept parameters, i.e. values to work with. The following
code shows how a parameter can be used in a basic method. Note that there is
no limit to the number of parameters that may be passed to a method, and
that the parameters may be of any type.
The following code shows a method that adds the two parameters that are
passed to it, and returns the result as an integer:
If a return type other than void is specified, then the method must have a
return statement at some point, or the application will not compile.
This does not prevent the application from compiling or executing, but it can
lead to logic errors. Because of this, a return statement may be used as a
break statement inside a method that returns void.
It is also possible to have multiple return statements inside a method. This can
be useful. For example:
The example above returns true if the first character in string str is equal to
the char character, regardless of whether the character is upper case or lower
case (which is why both have been converted to lower case before comparing
them). While the above example is perfectly acceptable, it is possible to reduce
the amount of code needed to perform this operation by leaving out the else
statement. The reason for this is that when the if code block is executed (and
this will happen when the condition is true), then the return true; statement is
executed and the execution of the method will not continue.
Remember that the example given is a very simple method. Most methods will
be more complex and are not usually so easy to simplify.
It is possible to have more than one method declared with the same name.
These methods are differentiated from one another by the parameters they
take. This means that there may be only one method with a particular name
that takes a certain set of parameters. This is known as overloading the
method.
// ToString method.
public override string ToString()
{
return Make + " – " + Model + ", in " + Condition +
" condition. Price : R" + Price;
}
The override keyword specifies that this method must override a method in the
base class (in this case Object). If the override keyword is not used, the
compiler will show a warning message during compilation. The
ToString()method is a special method that is called whenever an object is
written to the console. Many examples of this method are shown further on in
the guide.
1.5.6 Inheritance
Three classes that inherit from the Vehicle class (the Car, Truck and Motorbike
class) will now be created. This is actually a fairly simple process, because
most of the code needed has already been written for the Vehicle class, and
the new classes will inherit all of that functionality. What needs to be written is
the functionality that differs from the Vehicle class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace vehicleTracking
{
class Car
{
}
}
Now that there is a Car class, ensure that it inherits from the Vehicle class by
making the following modification:
Adding the code : Vehicle after the class declaration instructs the compiler that
this class inherits from the Vehicle class. Adding different constructors,
properties and methods as necessary will define how the Car class differs from
the Vehicle class.
The Car class is going to differ from the Vehicle class in that it will have a
property that stores the number of passengers the car can carry. In addition to
this, a custom constructor which will allow that property to be set when the
object is created, as well as an updated ToString() method which will display
this property in addition to the other information, is required.
// Constructor.
public Car() :base()
{
}
// Constructor.
public Car(string make, string model, eVehicleCondition condition, double price,
int passengerCapacity)
:base(make,model,condition,price)
{
PassengerCapacity = passengerCapacity;
}
In the above example, the constructor of the Vehicle class has been extended
using the base() command. The base() command specifies that the matching
method or constructor from the base class should be called before executing
the code of the method/constructor. Naturally, if the base() command is
omitted, then only the code in the method or constructor will be executed.
There are two constructors and the first ‘empty’ constructor is necessary to
store instances of the class in an array.
There is only one more requirement to complete the Car class: its own
implementation of the ToString() method. Once again, the base command may
be used. In this situation, however, a value is being returned, which means
that the use of the command will be slightly different.
Notice that the Visual Studio automatically generates some of the code as code
is being entered. The method should end up looking as follows:
// ToString method.
public override string ToString()
{
return base.ToString() + ", Passenger Capacity : " + PassengerCapacity;
}
This ToString()method in the Car class returns a string value made up of:
Ensure that the Car class has been completed according to the instructions in
this section, with the property, constructor and ToString() method.
Now create the Truck and Motorbike classes. They are both very similar to the
Car class, except that the Truck class will have a CargoCapacity property, and
the Motorbike class will have an EngineCapacity property. These properties will
take the place of PassengerCapacity for these two classes.
The following code shows what the code for the Truck class should look like:
namespace VehicleApplication
{
class Truck : Vehicle
{
private int mCargoCapacity = 0;
public int CargoCapacity
{
get
{
return mCargoCapacity;
}
set
{
mCargoCapacity = value;
}
}
// Constructor.
public Truck()
: base()
{
}
// Constructor.
public Truck(string make, string model, eVehicleCondition condition,
double price, int cargoCapacity)
: base(make, model, condition, price)
{
CargoCapacity = cargoCapacity;
}
// ToString method.
public override string ToString()
{
return base.ToString() + ", Cargo Capacity : " + CargoCapacity;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VehicleApplication
{
class Motorbike : Vehicle
{
private int mEngineCapacity = 0;
public int EngineCapacity
{
get
{
return mEngineCapacity;
}
set
{
mEngineCapacity = value;
}
}
// Constructor.
public Motorbike()
: base()
{
}
// Constructor.
public Motorbike(string make, string model, eVehicleCondition condition,
double price, int engineCapacity)
: base(make, model, condition, price)
{
EngineCapacity = engineCapacity;
}
// ToString method.
public override string ToString()
{
return base.ToString() + ", Engine Capacity : " + EngineCapacity;
}
}
}
There are four classes that will be used in the vehicleTracking application. The
functionality that will put these classes to practical use will now be
implemented.
Return to the Program class (Use either the File tab or the Solution Explorer).
1. The user needs to be able to add new Cars, Trucks and Motorbikes.
2. The program must be able to display a list of Vehicles by type.
3. The program must be able to display a list of all Vehicles.
// Variable declaration.
Vehicle[] vehicleArray = new Vehicle[50];
int numVehicles = 0;
Notice that an integer variable is used to hold the count of how many vehicles
are stored in the array. This will be used later to display the vehicles.
This method moves through the array and displays each of the vehicles, one
after the other. The numVehicles variable is used to ensure that the program
does not display vehicle objects that have not been instantiated.
The other three display methods must now be created. These methods will all
be very similar to each other, the only difference being the type of vehicle that
they display.
The above methods all make use of the is operator. The is operator is a special
operator that C# uses to determine if an object is of a specific class. In this
case, there is an array of Vehicles, but it is not known which one may belong
to the type Cars, Trucks or Motorbikes.
// Prompts the user for information and adds a vehicle to the array.
public void AddVehicle()
{
// Variable declaration.
Vehicle v;
char vehicleType;
int vehicleCapacity;
string vehicleMake;
string vehicleModel;
Vehicle.eVehicleCondition vehicleCondition;
double vehiclePrice;
switch(Char.ToLower(vehicleType))
{
case 'c': // Car
// Prompt for correct capacity type.
Console.Write("Passenger Capacity : ");
// Parse the input.
vehicleCapacity = Int32.Parse(Console.ReadLine());
// Create a new instance of the Car class.
v = new Car(vehicleMake, vehicleModel, vehicleCondition,
vehiclePrice, vehicleCapacity);
break;
break;
}
Console.WriteLine("Vehicle Tracking");
Console.WriteLine("------------------------------------");
Console.WriteLine("1. Add a vehicle");
Console.WriteLine("2. Display all vehicles");
Console.WriteLine("3. Display all cars");
Console.WriteLine("4. Display all trucks");
Console.WriteLine("5. Display all motorbikes");
Console.WriteLine("6. Exit");
Console.WriteLine("------------------------------------");
Console.Write("Please make your choice : ");
}
A switch … case statement determines which choice the user has made:
switch (c)
{
case '1': // Add a Vehicle
AddVehicle();
break;
case '2': // Display sll vehicles
DisplayAllVehicles();
break;
case '3': // Display all cars
DisplayAllCars();
break;
case '4': // Display all trucks
DisplayAllTrucks();
break;
case '5': // Display all motorbikes
DisplayAllMotorbikes();
break;
case '6': // Exit
Console.WriteLine("Goodbye!");
break;
default: // Invalid input
Console.WriteLine("Please enter a number between 1 and 6");
break;
}
// Pause.
Console.WriteLine("Please hit any key to continue...");
Console.ReadLine();
}
// constructor
public Program()
{
char choice = ' ';
The above while loop will repeat, displaying the menu until the user decides to
exit by choosing 6.
In the Main method, we simply need to create a new instance of the Program
class. We do not need to assign it to a variable as we do not refer to it again; it
is completely self-contained. Remember that when an instance is created, the
constructor is called. Thus, when the new Program instance is created, its
constructor is called and our application enters the menu loop.
#define TEST
//#undef TEST
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace preprocessorTest
{
class Program
{
static void Main(string[] args)
{
#if TEST
// This will only execute if TEST has been defined.
Console.WriteLine("TEST has been defined");
#else
// this will only execute if TEST has not been defined
Console.WriteLine("TEST has not been defined");
#endif
// Pause.
Console.ReadLine();
}
}
}
The above program shows how a basic #if … #else … #endif works. If the
comment before the line #undef TEST is removed (or if the line #define TEST
is commented-out), TEST would then no longer be defined and the if block
would no longer be compiled. The else block will be compiled instead. Notice
how the Visual Studio Professional 2013 automatically changes the colour of
code that will not be compiled so that it is greyed out.
#define TESTING_MODE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace preprocessorTest
{
class Program
{
static void Main(string[] args)
{
#if TESTING_MODE
#warning "Program compiled in testing mode..."
#endif
// Pause.
Console.ReadLine();
}
}
}
#define NO_COMPILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace preprocessorTest
{
class Program
{
static void Main(string[] args)
{
#if NO_COMPILE
#error "An error message."
#endif
}
}
}
The Math class provides methods that are used to perform mathematical
operations, ranging from simple square roots to more complicated
trigonometry.
The Math class is static, which means that an instance of the class does not
need to be created in order to use its methods. To use its methods it is merely
necessary to specify the Math class before the method name, like this:
returnValue = Math.methodName(parameters);
Table 8 shows some of the Math class methods. In the Example column, the
value in the commented line is the answer to the given operation (i.e.
Math.Abs(-5.95) = 5.95). Note that NaN refers to Not a Number. Some
mathematical operations may return NaN if the equation is invalid.
In addition to its methods, the Math class also contains some mathematical
constants. These constants are displayed in Table 9.
The following example shows how Math class methods can be used:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MathClassTest
{
class Program
{
static void Main(string[] args)
{
Console.Write("Please enter a number: ");
int num = Int32.Parse(Console.ReadLine());
Console.WriteLine();
Console.WriteLine("The square root of " + num + " is " +
Math.Sqrt(num) + ".");
Console.ReadLine();
}
}
}
Numbers generated by the Random class are not true random numbers;
because the numbers are generated by an algorithm, they are in reality only
pseudo-random numbers. What this means is that if the starting point
(referred to as the seed) of the algorithm is the same in two separate cases,
then the ‘random’ numbers generated will be the same. The current time (in
milliseconds) is used if no seed is specified for the Random class.
Random random = new Random(); // Create a new instance of the Random class
// without specifying a seed.
Random random2 = new Random(8); // Create a new instance of the Random class
// specifying a seed value of 8
A maximum value may be specified for the random number. Note that the
returned value will always be less than the maximum value.
Both the minimum and the maximum value of the range for a random number
may be specified.
The Random class can also return numbers as the double data type.
// Get the next random number between 0.0 and just below 1.0.
int randomNumer = random.NextDouble();
Multiple choice
3. Which one of the following would be the most appropriate variable type
for variable x?
x = 'a';
a. uint
b. byte
c. int
d. char
a. Hello, Gerald.
b. Hello, userName.
c. Hello, {0}.
d. Hello, {Gerald}.
True/False
Multiple response
if(***)
{
Console.WriteLine("Condition met!");
}
}
Selection
This unit introduces you to object and component programming with C#.
Classes and objects will be covered in more depth.
This unit counts 10% towards part A of the C# mark, and you will have 12
days to complete it. The time and marks are scheduled as follows:
Reading 10 days
Exam preparation and exam 2 days 10%
class ClassName
{
// Variables you are going to use in the code below.
string myStr;
<Class_members>
=> <Data_members> <Function_members>
=> <Function_members> => <Methods>
=> <Nested_types> => <Constructors>
=> <Destructor>
=> <Properties>
=> <Indexers>
<Data_members>
=> <Operators>
=>
<Member_variables>
=> <Constants>
=> <Events>
Methods are also known as ‘behaviours’ and ‘functions’. Furthermore, these are
divided into instance and static methods.
Static methods
A method that is static belongs to the class, not the instance from which it is
called. Due to this, static methods cannot access any members that are not
static themselves.
Instance methods
Instance methods are invoked on an instance of a class. In this case, the
method belongs to that instance, as opposed to belonging to the class itself.
Note that any method that is not declared as static automatically becomes an
instance method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test
{
class PubPoint
{
// Public variables declared.
public int x;
public int y;
}
class MainClass
{
static void Main()
{
PubPoint pp = new PubPoint();
x = 10, y = 15
namespace Test
{
class P
{
// Protected variable is declared and initialized.
protected int x = 123;
}
class Q : P
10
class Employee
{
private int i;
// Private access by default.
double d;
}
2.1.4 Fields
Fields store the data that is necessary in order for the program to function. For
example, a class called ReleaseDate might contain three integer fields: one for
day, one for month and one for year. Fields are declared in the class block by
specifying the access level of the field, followed by the type of the field, and
then the name of the field.
Vehicle
numWheels
numDoors
numPassengers
speedKPH
Move()
Fill()
The Vehicle class has two methods: Move() and Fill(). It has four attributes
(fields) called numWheels, numDoors, numPassengers and speedKPH.
Remember that attributes describe the object, whereas methods are the
behaviours of the object.
Static fields belong to the class itself; instantiated objects cannot see this field.
Therefore, static fields need to be accessed using the className.VariableName
notation, as opposed to instanceName.VariableName.
It is also important to know the difference between read-only and const fields.
The read-only and const fields are similar in that neither of them can be
modified. The difference between them is when they are initialised. Const fields
are initialised during compilation, and read-only fields are initialised during
runtime. A read-only field can only have a value assigned to it in two ways: (a)
in the initialisation statement, or (b) in the constructor of the class in which the
field was declared. Attempting to modify the value in any other manner will
throw a compilation error.
2.1.5 Constructors
Constructors have the same name as the class of which they are members.
Constructors do not return values (i.e. they have no return type) and they can
accept as many parameters as needed.
The example given below is very similar to the one discussed earlier in static
methods.
Static constructors can only access static fields. Classes are loaded before any
instances are created; thus instance fields may not yet have been initialised.
At this point, not even the instance constructor has been invoked. In some
cases, it may never be invoked. Static constructors are primarily used to
initialise the class.
static Randomizer()
{
// The current date is stored in a variable.
DateTime dt = DateTime.Now;
result = dt.GetHashCode();
}
}
Static constructors are very similar to instance constructors in that (a) they do
not have a return type, and (b) they share their name with the class in which
they are declared. However, they cannot accept parameters.
Static constructors cannot be called by any programs. They are only invoked
when a class is loaded. Unlike an instance constructor, a static constructor has
no specific sequence of operations for when it is invoked, but there are a few
conditions.
Got a new object. Need OK. Use this space. Used to have
memory. some data but anyway…
0001010101
Num newNum1
When the newNum1 variable is accessed, the garbage data that was stored in
memory is loaded. This is why C# offers many features to assist initialisation
of variables.
The instance variable declaration allows the initial value for the instance
variables to be specified, and any instance variables that have not been
explicitly assigned a value will automatically get default values during runtime.
Constructors are called whenever an instance of a class is created. If a
constructor is not provided, an empty one will be used.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConstructorExample
{
class ConstructorEx
{
string greeting;
string name;
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace thisExample
7 {
8 class thisEx
9 {
10 string greeting;
11
12 public thisEx(string greeting)
13 {
14 this.greeting = "Hello there!";
15 Console.WriteLine("Instance variable greeting: " +
16 this.greeting);
17 Console.WriteLine("This is the parameter received: " + greeting);
18
19 // Setting the instance variable to the parameter:
20 this.greeting = greeting;
21 Console.WriteLine("Changed the instance variable to: " +
22 this.greeting);
23 }
24
25 static void Main(string[] args)
2.1.6 Destructors
~WebSite() {}
The ‘~’ symbol is called a tilde and all destructors begin with this symbol. Their
parameter list is always empty and they do not return any values.
System.GC.Collect();
However, this does not necessarily guarantee that garbage collection will
occur. It is always important to take care about how a destructor method is
implemented, or problems could arise.
Just as every class has a default constructor, so every class has a default
destructor. The constructor is called when an object is instantiated with the
new keyword. Only the Garbage Collector can call destructors.
2.1.7 Indexers
Indexers allow instances of a class to be indexed just like an array. They are
similar to properties with one important difference: their accessors take
parameters. Recall that a get accessor returns a value and a set accessor
(referred to as a mutator) assigns a value.
The this keyword defines the indexers, and the value keyword is used to define
the value being assigned by the set indexer. Indexers can have more than one
formal parameter, for example, when accessing a two-dimensional array.
On line 11, a private string array is declared. On line 13, the indexer for this
class is declared. Note that the this keyword is used. This means that a static
indexer is not allowed. The this keyword is used because the indexer itself has
no name. On lines 37 to 39, the name of the object is simply being used to
access the indexer, e.g. cb[0]. The syntax cb.chocolates[0] is not used.
2.2.1 Inheritance
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace BaseClassExample
8 {
9 public class Mammal
10 {
11 protected string name = "Rudolph the Dolphin";
12 protected string species = "Bottle nose dolphin";
13
14 public virtual void GetInfo()
15 {
16 Console.WriteLine("Name: {0}", name);
17 Console.WriteLine("Species: {0}", species);
18 }
19 }
20
21 class Dolphin : Mammal
22 {
23 public string age = "6";
24
25 public override void GetInfo()
26 {
27 // Calling the base class GetInfo method:
28 base.GetInfo();
29 Console.WriteLine("Age: {0}", age);
30 Console.ReadLine();
31 }
32 }
33 class BaseClassEx
34 {
35 public static void Main()
36 {
37 Dolphin d = new Dolphin();
38 d.GetInfo();
39 }
On line 21, the Dolphin class (which inherits the Mammal class) is defined. On
line 25, the GetInfo() method, which was created on line 14, is overridden. This
means that the GetInfo() class is available to the Mammal class and to the
Dolphin class. On lines 11 and 12, variables are declared protected. This allows
the BaseClassEx class on line 33 (which is in the same file) to access the
variables. The protected keyword allows access to all of its sub-classes.
In the above example, three classes are defined, namely: Mammal, Dolphin and
BaseClassEx. The Mammal class has two variables that have been declared
using the protected modifier. Due to these variables being protected, they are
only accessible within (a) the class in which they were declared (Mammal), and
(b) any class that is derived from that class (in this case, Dolphin). The
Mammal class also implements a virtual method called GetInfo(). When a
method is declared as being virtual, derived classes can declare their own
implementations of the method and override the existing one.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace AbstractExample
7 {
8 abstract class Mammal
9 {
10 abstract public void MakeSound();
11 }
12
13 class Dolphin : Mammal
14 {
15 public override void MakeSound()
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace CallingBaseClassMembersExample
7 {
8 class Mammal
9 {
10 protected string declaration = "Dolphins swim faster than humans!";
The Dolphin class inherits from the Mammal class on line 13. On line 10, the
Mammal class only has one attribute, called declaration; because it is a
protected member, it can be accessed by inheriting classes.
class Base
{
public void Var()
{
}
}
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace HidingBaseClassMembersExample
8 {
9 class Mammal
10 {
11 protected string declaration = "Dolphins swim faster than humans!";
12 }
13
14 class Dolphin : Mammal
Although a warning message is produced, the program will still compile and
execute. This is because Dolphin.declaration is being hidden. The following
warning will be displayed in the Error List at the bottom of the screen shown in
Figure 22:
2.2.1.5 Versioning
It may seem inconvenient that a class member which has the same name as
any of the names in the base class cannot be used. However, this is not true.
The compiler issues warning messages because such coding can cause subtle
bugs which were hard to trace in earlier programming languages.
The following example shows how the previous program has been modified to
run without any warning messages being displayed.
NOTE The declaration for declaration in the Dolphin class on line 16 now has
the new keyword in front of the declaration. This alerts the compiler
about the base class member declaration which is being hidden.
When the program is run, it should now compile and execute without any
warning messages being displayed.
To ensure this, the class is declared sealed, so that other classes cannot inherit
from it and modify its behaviour. If another class attempts to derive from the
MyEncryptor class, the application will not compile.
2.2.3 Polymorphism
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace ImplementingPolymorphismExample
8 {
9 class Mammal
10 {
11 public virtual void Movement() { }
12 }
13
14 class Dolphin : Mammal
15 {
16 public override void Movement()
17 {
18 Console.WriteLine("Dolphins swim!");
19 }
20 }
21
On line 35, an array is created with two objects. On line 37, a foreach loop is
used to iterate through all the elements of the array. Note that the type is
declared as Mammal. They are implicitly of the Mammal type because all the
classes inherit from the Mammal class. They all share the Movement() method,
but each class implements it differently. This demonstrates the concept of
polymorphism.
Creating mammals...
Dolphins swim!
Bears run!
In Figure 23 three classes are declared, namely: Vehicle, LandVehicle and Car.
LandVehicle is derived from Vehicle, and Car is derived from LandVehicle.
Vehicle defines a virtual method called Drive(), and the Car class overrides that
method. LandVehicle does not override the Drive() method.
LandVehicle
Vehicle driving!
Vehicle driving!
Car driving!
As is evident from the above example, when a method is called, the most-
derived implementation of that method is always executed. When the Drive()
method is called on the LandVehicle instance:
1. The application first checks the class itself (LandVehicle) to see if the
method exists, and finds that it does not.
2. The application then checks the Vehicle class (the class from which
LandVehicle is derived) to see if the method is defined there, and finds a
matching implementation.
3. That method implementation is then executed.
1. The application checks the class itself (Car) to see if the method exists,
and finds a matching implementation.
2. That method implementation is then executed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PolymorphicProperties
{
abstract class Person
{
protected string name;
protected string surname;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PolymorphicProperties
{
class Friend : Person
{
protected string telNo;
namespace PolymorphicProperties
{
class Program
{
static void Main(string[] args)
{
Friend f = new Friend("John", "Doe", "0119998823");
Console.WriteLine(f.Details);
Console.ReadLine();
}
}
}
John Doe
0119998823
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PolymorphicIndexers
{
class PersonList
{
protected string[] names;
protected string[] surnames;
// Constructor.
public PersonList(int numPeople)
{
names = new string[numPeople];
surnames = new string[numPeople];
}
// Indexer.
public virtual string this[int index]
{
get
{
// If the index is invalid.
if (names.Length < index || names[index] == "")
{
return "Nobody";
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PolymorphicIndexers
{
class FriendList : PersonList
{
string[] telNumbers;
namespace PolymorphicIndexers
{
class Program
{
static void Main(string[] args)
{
// Create an instance of each class.
PersonList pl = new PersonList(3);
FriendList fl = new FriendList(3);
Console.WriteLine();
Console.WriteLine("Friend List: ");
Person List:
John Doe
Jane Doe
Cameron Doe
Friend List:
Elle Burger
011999220
Brian Stunt
120983092
Karl Labert
012332002
Method overloading helps produce code that is both reusable and easy to
understand. Different versions of a method may be defined in a class. But how
does the C# compiler know which method to call? It decides which method to
invoke based on the number and type of arguments passed to it. This is also
referred to as the signature of the method. If there are two methods with the
same name and the same number and type of passed arguments, a compile-
time error occurs. However, it is possible to have two methods with the same
name and the same number of arguments as long as the argument types differ
(i.e. the methods have different signatures).
The first overloaded method requires two integer values, so the compiler will
generate code that calls this overload. The second overloaded method requires
three integer values.
The following example shows how a method can be overloaded several times:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OverloadingExample
{
class Program
{
static void Main(string[] args)
{
// Create an instance of this class.
Program p = new Program();
// Pause.
Console.ReadLine();
}
public Program()
{
// Call the overloaded method.
Greet();
Greet("Joseph");
// Try changing 'false' to 'true' and observe the result.
Greet("Arnold", false);
}
The procedure for overloading indexers is very similar to that used for
overloading methods. Several declarations for this[] can be included, each with
a different set of parameters or signature. In the following example, a class is
created which acts much like an array, except that values are stored according
to a key instead of an index. However, the values can still be accessed via an
index due to an overloaded indexer.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverloadingIndexers
{
class KeyedList
{
protected string[] values;
protected string[] keys;
protected int num = 0;
if (keys.Contains(key))
{
for (int loop = 0; loop < num; loop++)
{
// If a match has been found.
if (keys[loop] == key)
{
index = loop;
// Break out of the loop.
break;
}
}
}
return index;
}
return null;
}
}
}
namespace OverloadingIndexers
{
class Program
{
static void Main(string[] args)
{
// Create a new KeyedList.
KeyedList jobList = new KeyedList(3);
jobList["Andrew"] = "Plumber";
jobList["Harry"] = "Electrician";
jobList["Edgar"] = "Unemployed";
Console.WriteLine();
Console.WriteLine("Displaying by key : ");
Console.WriteLine("[Andrew] – " + jobList["Andrew"]);
Console.WriteLine("[Harry] – " + jobList["Harry"]);
Console.WriteLine("[Edgar] – " + jobList["Edgar"]);
Console.ReadLine();
}
}
}
Displaying by index :
[0]Andrew – Plumber
[1]Harry – Electrician
[2]Edgar – Unemployed
Displaying by key :
[Andrew] – Plumber
[Harry] – Electrician
[Edgar] – Unemployed
Overloaded operators only work in the class in which they are defined and not
all operators can be overloaded, as illustrated in Table 11.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OverloadingOperatorsExample
{
class Year
{
int totalMon = 0;
int numYear = 0;
static int increment = 1;
Compound operators (i.e. operators that are made up of two other operators,
such as +=, *=, etc.) cannot be explicitly overloaded. However, when a binary
operator is overloaded, its corresponding compound operator will assume the
same overloaded behaviour. So, for example, if the + operator for a specific
class is overloaded, the += operator will use the new + operator to calculate
the result.
A try … catch block consists of a try section followed by one or more catch
clauses, each of which handles specific exceptions that can occur.
The simplest form of a try … catch block has the following layout:
try
{
// Try executing some code.
}
catch (Exception e)
{
// Error occurred. Handle error.
}
The try block contains the code that may cause an exception. The block will
execute until an exception is thrown. If no exception is thrown, then the
program will continue executing code after the catch statement.
The argument that is passed to the catch statement (in this case Exception e)
specifies exactly which type of exception to catch. The catch block will then
catch any exception of that type, as well as any exception that is derived from
that type. Because of this, the catch block in the example above will catch any
type of exception (as every exception is derived from the Exception class).
It should also be noted that a catch clause can be used without any
arguments; if this is done, any type of exception will be caught. Such a clause
is referred to as a general catch clause.
A throw statement can also be used inside the catch block to rethrow the
exception that has been caught by the catch statement. While it is not
common practice, this can be used, for example, if some specific operation
must be performed when an error occurs, but must still allow the exception to
be caught by another try … catch statement. To rethrow the exception
currently handled by a catch clause without parameters, use the throw
statement without an argument.
Exceptions can be caught at any level. What this means is that an exception
does not necessarily have to be caught in the same place as it was thrown – so
long as the exception ultimately falls within a try … catch statement. For
example, if a method in a class has the potential to throw an uncaught
exception, that exception will still be caught if the method call is placed inside
a try … catch statement.
On line 17, a new class MyClass is created. Lines 19 to 37 include the whole try
… catch block. On line 26, the catch clause is specific as to which exception
(ArgumentNullException) must be caught. When this exception is caught, a
specific message is displayed on line 28 with the error that occurred.
The catch statement on line 33 is more general. This means that any other
exception that might occur, apart from the ArgumentNullException, will be
caught here. This is useful when it is not known exactly which exception will
occur. Once again, a specific message is displayed on line 35 when Exception e
occurs.
Lastly, a method, MyFn(), is created on line 40. This method is called on line
22 and includes string s (which was declared as null on line 20) and then puts
that value in the place of s on line 21, x.MyFn(s). This null value is then sent to
the method on line 39. The if statement checks if s is null and then throws the
ArgumentNullException if it is indeed null.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultipleExceptionProgram
{
class Program
{
static void Main()
{
string one = "5";
try
{
Console.WriteLine("Trying to convert two strings.");
Console.WriteLine("First string: {0}", Int32.Parse(one));
// If uncommented, the following line will cause a
// FormatException error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ThrowException
{
class Program
{
static void Main()
{
Program te = new Program();
try
{
while (e != null)
{
Console.WriteLine("Inner: {0}", e.Message);
// Set e to the InnerException. This will go on until the
// chain of exceptions is exhausted.
e = e.InnerException;
}
}
finally
{
Console.WriteLine("Finally clause in the Main method.");
Console.ReadLine();
}
}
void GenerateException()
{
try
{
string one = "Not a number.";
Console.WriteLine(Int32.Parse(one));
}
catch (FormatException e)
{
// Throw a new exception:
Console.WriteLine("Format exception from GenerateException.");
When an exception occurs, execution of the code inside the try block is
stopped. This often means that lines of code are not necessarily executed.
Some resource clean up, such as closing a file, might still need to be
performed even if an exception is thrown. This can be accomplished by using a
finally block. A finally block is always executed, regardless of whether an
exception occurs or not.
namespace FinallyBlockProgram
{
class Program
{
static public void Main()
{
int[] array1 = { 0, 0 };
int[] array2 = { 0, 0 };
try
{
// This statement will thrown an exception.
Array.Copy(array1, array2, -1);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine("Error: {0}", e);
}
finally
{
Console.WriteLine("This statement is always executed.");
Console.ReadLine();
}
}
}
}
As previously mentioned, any class that is derived from the Exception class (or
any of its sub-classes) is automatically also an exception. The following
example shows how a custom exception can be created. Note that the
exception has to inherit from the Exception class and call the constructor
method of the base Exception class.
Consider the case of a group of children in a class. It is not unusual that two
children have the same first name, for example, John. If their surnames differ,
these two may be differentiated on this basis. But what if their surnames are
also the same?
One could be called ‘blonde John Smith’, and the other one ‘brunette John
Smith’. Or, age could be used as a criterion. If there is one John in the classA
and another John in the classB, the first John may be addressed as follows:
// Note: The names found here are the classmates in the class A.
// This John is the John in class A.
John went to play soccer.
ClassA.John
using ClassA;
John j = new John();
Declaring a namespace can help control the scope of the class and method
names in larger programming projects. The namespace keyword is used to
declare a scope. The ability to create scopes within the project helps organise
code. Syntax similar to the code snippet below could be used to name each
child without confusion.
Johannesburg.SunflowerSchool.ThirdGrade.SecondClass.John;
using Johannesburg.SunflowerSchool;
/* Because of the namespace declaration, we know that ThirdGrade refers to the
ThirdGrade of the SunflowerSchool in Johannesburg. */
ThirdGrade.FourthClass.Sarah;
Secondly, the .NET Framework classes use namespaces to organise the many
classes found in the class library. For example, declaring using System at the
top of the program allows for:
Console.WriteLine();
Instead of:
System.Console.WriteLine();
The main difference between a class and a struct lies in the way in which they
are stored in memory. Look at the following example of a struct declaration:
It is evident from the above example that the way in which a struct and a class
are declared is very similar, the only noticeable difference being the use of the
struct keyword instead of the class keyword. There are, however, significant
differences between the two. As with classes, structs define new data types
which can then be used and reused in many applications. However, while
classes define a reference type, structs define a value type.
A reference type stores a reference to an object. The variable itself does not
actually contain the object, but it stores the memory address where that object
is stored. All reference types are stored on the heap. A value type, however,
actually contains its data within itself. All value types are stored on the stack.
The heap and the stack are two sections of memory. Memory on the heap is
allocated in chunks as necessary, and then released and reallocated over time.
This can cause fragmentation (where data becomes fragmented, i.e. it is
stored in several segments, each in a different memory location) which leads
to the need for additional memory management. Memory on the stack is
stored in a Last In-First Out (LIFO) manner whereby the data that was last
stored (last in) is the first that can be removed (first out). This is more efficient
than heap allocation, as it avoids the issue of fragmentation.
Push
STACK HEAP
Pop
SP
Objects on the stack are faster to allocate and de-allocate. However, the
amount of memory available on the stack is more limited than memory on the
heap. If the stack memory is exhausted, a StackOverflowException is thrown.
It is therefore generally better to use classes for larger, more complicated
objects. Because structs are stored on the stack, they are more efficient than
classes, but due to the limited availability of stack memory, structs are better
suited to smaller, less complicated objects.
In C#, another difference between classes and structs is that structs do not
allow for inheritance. Because of this, a struct cannot be sealed or abstract,
nor can the protected modifier be used for any of the fields.
Class Struct
System.Boolean (bool)
System.Byte (byte)
Both class and struct System.Char(char)
inherit from object System.Double(double)
implicitly. System.Int32 (int)
System.String (string)
In C#, this unified type system is referred to as the Common Type System
(CTS).
The following example shows how a value can be boxed and then unboxed
again:
class BoxingAndUnboxing
{
// Entry point of the application.
static void Main()
{
int value = 999;
// Boxing.
object boxedValue = value;
// Unboxing.
int unboxedValue = (int) boxedValue;
}
}
Because all value types in C# are actually structs, it follows that customised
value types can be created by using structs. This is very similar to creating a
new class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StructExample
{
public struct Currency
{
private double amount;
Amount = R 5.62
Implicit casting happens automatically when data will not be lost when the
type is converted. For example, implicit conversion will not happen in
converting a double type to an integer, because the values following the
decimal point would be lost. However, an integer can be converted into a
double, because the double data type can store all that an integer can, and
more.
int radius = 5;
double c = 3.14 * 2 * radius
In the above example, the two integer values (2 and radius) are first implicitly
converted to the double data type before the calculation is performed. Implicit
conversion can also take place anywhere a mathematical operation is
performed, such as inside a condition. Implicit conversion will only take place if
it is necessary for the calculation being performed.
double d = 3.14;
int i = (int)d * 2;
In the above example, the double value ‘d’ is converted to an integer before
multiplying it by 2. The end result would be 6, as converting a double to an
integer removes all decimal information. Pay careful attention when using
explicit casting, and only use it only when necessary.
int long
Problems may arise when the data type is assigned to a type that is smaller
than itself, as shown in Figure 27.
When an interface is implemented in a class, then that class inherits all the
methods, properties and indexers of the interface declaration. However, that
class must implement all of those members or it will not compile. What then is
the point of using the interface if all the methods must be implemented
anyway?
Recollect in the earlier section on polymorphism that the different classes can
all be treated in the same way, so long as they are all derived from the same
base class. Interfaces function in much the same way. If two classes both
implement the same interface, then they can both, for example, have
instances of them stored in an array which is declared as storing the type of
that interface. It follows from this that those methods, properties and indexers
which were defined in the interface on these objects may be called, even if
their exact type is not known.
Interfaces share many similarities with abstract classes, but they are not the
same thing. Abstract classes are used for abstraction, whereas interfaces
define specification. Members of an abstract class may only contain
implementations if they are not defined as abstract themselves. Derived
classes must implement abstract class members, but they do not have to
implement any other members that are declared as virtual. When
implementing an interface, however, all methods, properties and indexers
need to be overridden.
Classes and structs can implement interfaces in a manner that is similar to the
way in which classes inherit from base classes. A class or struct can implement
more than one interface. When a class or struct implements an interface, it
only inherits the method/property/indexer names and signatures.
namespace InterfaceExample
{
// Creating an interface.
interface Comparable
{
// Declaring three Boolean variables which will receive values from
// the MyInteger class.
bool IsEqualTo(Object o);
bool IsGreaterThan(Object o);
bool IsLessThan(Object o);
}
}
namespace InterfaceExample
{
class MyInteger : Comparable
{
// The value of this object.
int storedValue;
// Property used to retrieve the storedValue. It will be clear in the
// Main class that the storedValue will be either one or 15.
public int Value
{
get
{
return storedValue;
}
set
{
storedValue = value;
}
}
// Constructor.
public MyInteger(int newValue)
{
Value = newValue;
}
namespace InterfaceExample
{
class Program
{
// The Main() method of the application.
static void Main(string[] args)
{
// Creates an instance of the MyInteger class with two different
// values.
MyInteger one = new MyInteger(1);
MyInteger fifteen = new MyInteger(15);
// Pause.
Console.ReadLine();
}
}
}
The result is
15 > 1 == True
1 < 15 == True
1 = 15 == False
1 = 1 == True
// Drivable interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Polymorphism
{
// Creating an interface.
interface Driveable
{
// Declaring variables which will receive values from the Vehicle class
void Drive();
void Steer(bool steerRight);
void Accelerate(double accelerationAmount);
void Break(double breakingStrength);
}
}
namespace Polymorphism
{
// Creating an abstract Vehicle class.
abstract class Vehicle
{
// Instance variables.
public string name;
public double maxSpeed;
public double currentSpeed;
// Constructor.
public Vehicle()
{
}
// Car Class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Polymorphism
{
// Inherit from Vehicle, implement Driveable.
class Car : Vehicle, Driveable
{
// Call the base class constructor.
public Car(string name, double maxSpeed, double currentSpeed)
: base(name, maxSpeed, currentSpeed)
{
}
// Go faster.
public void Accelerate(double accelerationAmount)
{
if (accelerationAmount > 0 & currentSpeed < maxSpeed)
{
// Change in velocity = acceleration * time;
// for this example, assume time = 1 second.
if (currentSpeed + accelerationAmount > maxSpeed)
{
currentSpeed = maxSpeed;
Console.WriteLine("Car: Maximum speed of " + maxSpeed +
"km/hr reached!");
}
else
{
currentSpeed += accelerationAmount;
Console.WriteLine("Car: Accelerated to " + currentSpeed +
"km/hr.");
}
}
else if (currentSpeed == maxSpeed)
{
Console.WriteLine("Car: Cannot accelerate, maximum speed " +
"reached!");
}
}
// Slow down.
public void Break(double breakingStrength)
{
if (breakingStrength > 0 & currentSpeed > 0)
{
if (currentSpeed – breakingStrength < 0)
{
currentSpeed = 0;
Console.WriteLine("Car: Breaked to a standstill.");
}
else
{
currentSpeed -= breakingStrength;
Console.WriteLine("Car: Decelerated to " + currentSpeed +
"km/hr.");
}
}
}
// Truck Class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Polymorphism
{
class Truck : Vehicle, Driveable
{
// Call the base class constructor.
public Truck(string name, double maxSpeed, double currentSpeed)
: base(name, maxSpeed, currentSpeed)
{
}
// Go faster.
public void Accelerate(double accelerationAmount)
{
if (accelerationAmount > 0 & currentSpeed < maxSpeed)
{
// Change in velocity = acceleration * time;
// for this example, assume time = 1 second.
if (currentSpeed + accelerationAmount > maxSpeed)
{
currentSpeed = maxSpeed;
Console.WriteLine("Truck: Maximum speed of " + maxSpeed +
"km/hr reached!");
}
else
{
currentSpeed += accelerationAmount;
// Program class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Polymorphism
{
class Program
{
static void Main(string[] args)
{
Driveable[] vehicles = new Driveable[2];
// Pause.
Console.ReadLine();
}
}
The following example creates a Rectangle class which can draw a rectangle on
the screen. This rectangle can be scaled up or down, as well as compared with
other rectangles:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MutlipleInterfaceExample
{
// Creates new Comparable interface.
interface Comparable
{
bool IsEqualTo(Object o);
bool IsGreaterThan(Object o);
bool IsLessThan(Object o);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MutlipleInterfaceExample
{
// Creates new Scaleable interface.
interface Scaleable
{
double Scale
{
get;
set;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MutlipleInterfaceExample
{
// Creates the Rectangle class which implements the Scaleable and Comparable
// intefaces.
class Rectangle : Scaleable, Comparable
{
double width;
double height;
// Constructor.
public Rectangle()
{
width = 0;
height = 0;
}
// Constructor.
public Rectangle(double width, double height)
{
this.width = width;
this.height = height;
}
return false;
}
return false;
}
return false;
}
Console.WriteLine();
}
return returnString;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MutlipleInterfaceExample
{
class Program
{
static void Main(string[] args)
{
// Create two rectangles, x and y.
Rectangle x = new Rectangle(5, 5);
Rectangle y = new Rectangle(5, 5);
// Display rectangle x.
Console.WriteLine(x);
// Display rectangle x.
Console.WriteLine(x);
// Pause.
Console.ReadLine();
}
}
}
/\/\/\/\/\
/\/\/\/\/\
/\/\/\/\/\
/\/\/\/\/\
/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
/\/\/\/\/\/\/\/\/\/\
True/False
Multiple choice
2. What is the concept called that uses a method in more than one way?
a. Operator overriding
b. Method overriding
c. Method overloading
d. Exception handling
using System;
public Example()
{
ex = new Example("Stamp", "Green", 10);
}
using System;
a. 2
b. 0
c. 1
d. 3
Multiple response
This unit introduces you to object and component programming with C#.
This unit counts 80% towards part A of the C# mark, and 13 days have been
allocated to complete it. The time and marks are scheduled as follows:
3.1.1 Delegates
Delegates are used to enable late-bound operations. What this means is that a
delegate may be used to call a method, even if the exact method to call is only
decided at runtime.
When defining a delegate, the argument types and the return values need to
match those of the method. The signature of a single-cast delegate is shown
below.
result-type: the result type, which matches the return type of the function.
identifier: the delegate name.
parameters: parameters that the function takes.
Examples:
The example below is a very basic one, demonstrating how delegates work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateExample
{
// Delegate declaration:
public delegate void myDelegate();
class DelegateEx
{
public static void function()
{
Console.WriteLine("The delegate called the function...");
Console.ReadLine();
}
// Invocation:
myDelegate();
}
}
}
The following example declares a delegate that takes a single string parameter
and has no return type:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateExample
{
class Program
{
// Define the CalculateFuelUsage delegate.
public delegate double CalculateFuelUsage(int seconds, double
vehicleWeight, int engineCC);
// Pause.
Console.ReadLine();
}
Delegates are multicast. In other words, they can point to more than one
method at a time. The implication of this is that when the delegate is called,
each of the methods to which it points will also be called.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateExample2
{
class Program
{
// Define the functionDelegate delegate.
public delegate void functionDelegate();
public Program()
{
// Declare the delegate.
functionDelegate function;
Console.WriteLine("======================");
// Pause.
Console.ReadLine();
}
FUNCTION1 CALLED...
FUNCTION2 CALLED...
FUNCTION3 CALLED...
======================
FUNCTION2 CALLED...
FUNCTION3 CALLED...
When an event occurs (e.g. a button is clicked, or the user closes a window),
that event can trigger an event-handler which will execute code as necessary.
All Windows forms controls have several events, and many of them are
common to the different control types. These events are in fact delegates.
When the event occurs, the application will call the delegate, which will in turn
call any methods (the event-handlers) to which it may have been pointing.
The Windows form is the base of all GUI programming and contains
functionality to create an application. A form contains all the components
needed to create these applications. The components include the Button,
Label, RadioButton, TextBox and many more. The Windows form is a square
container on the screen into which other components are placed.
All GUI components inherit from the Form class which is found in the
System.Windows.Forms namespace.
3.2.2 Controls in C#
The most common controls are listed and explained in Table 12. Each one of
these will be dealt with in greater detail later. It is a good idea to customise all
control names so that they are easier to identify. Give the control a descriptive
name with the control’s appropriate prefix.
Table 12 – Controls
Control Custom Prefix Description
Controls that are clicked to perform a certain
Button btn
action.
Clicking on a CheckBox causes it to switch
CheckBox chk
between a checked and unchecked state.
A drop-down list of choices. It performs
ComboBox cb similarly to the ListBox. The difference is that
a ComboBox is more compact than a ListBox.
Used to display text. Label controls cannot be
Label lbl
edited.
A list of items that is displayed inside a box.
ListBox lst
Multiple items can be selected.
A blank form used for organisation and
Panel pnl
layout.
Panel
control
ListBox
control
ScrollBar
Select FILE > New > Project in Visual Studio (refer to Figure 29).
Click the Windows Forms Application icon, and enter a name for the
project, e.g. MyFormProject.
The Form1.cs [Design] tab is presented upon creation of a new Windows Form
Application while the Start Page tab closes automatically (as shown in Figure
The Toolbox tab appears on the left hand side of the screen, close to the top
where the page tabs are (as shown in Figure 32).
Text Text in the form’s title bar (at the top of the form).
Common Methods
Close Closes form and releases all resources.
Hides the form (does not release resources like Close
Hide
does).
Show Displays a hidden form.
Common Events
Occurs before a form is shown. The IDE generates a
Load default event-handler when the programmer double-clicks
on the form in the designer.
If the Toolbox tab is not displayed as described above, go to VIEW > Toolbox
(refer to Figure 34). It will then be displayed on the left-hand side of the
screen.
A little cross appears and this can be used to position the component on the
Windows form. The control can also be dragged from the Toolbox to the
desired position (refer to Figure 35).
Click on the empty form after having selected Label control. A label will be
created as shown in Figure 36.
The Properties window for the component that was added to the Windows form
appears in the bottom right hand corner. If it is not there, select View >
Properties Window. Figure 37 shows how the Properties Window may be
opened, and Figure 38 shows what the Properties window looks like.
The size of a control can be changed by placing the cursor over the edges of
the control.
In the situation where some code is to be added, but not a control, simply
right-click on the empty form and select View Code. Alternatively, select
View > Code or simply press <F7>.
The following will be displayed in the editor window after the Button has been
double-clicked:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MyFormProject
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
NOTE This creates another tab. There are now two .cs files open. One is
the Design file, and this is indicated by [Design] in square brackets
which appears after the file name. The other file, which has just been
opened, is the source code file.
Notice how the class is defined as partial; this means that this source file is
not the entire class. The rest of it is defined elsewhere. In this case, there is
another source file that contains the definition needed to create the Form
interface. This file can be viewed by right-clicking on the Form1.Designer.cs in
the Solution Explorer and clicking View Code. However, this file should not be
modified as it is automatically generated by the Visual Studio Professional
Design View.
The current form does not contain much functionality, but this will be added in
the next section.
3.2.4 Events
Events and delegates are closely related. This is because flexible event-
handling requires that the response to the event is sent to the appropriate
handler.
Events
Button
List of
Events
Current
Event
Handler
Figure 43
Figure 44
Click OK to go back to the Form1 window and the Label control changes as
shown in Figure 45:
The following table describes properties and methods that are common to all
controls:
3.2.5.1 Anchoring
Controls can be anchored or docked. When a control is anchored, it means that
control may be dynamically resized with the form. The Anchor property
describes an anchoring position for the control. When a control is anchored on
a form and the form is then resized, the control will remain a fixed distance
away from the form sides. Controls are anchored to Top, Left by default, so
there are no ‘un-anchored controls’.
If the form above is resized without anchoring the control, the result is as
shown in Figure 47, since the position of the control does not depend on the
size of the form.
Now change the Anchor property of both controls to Bottom, Left and Right.
The Anchor property is in the Properties window, as shown in Figure 48.
The Button control will, in this case, always remain a fixed distance from the
bottom of the form and will either increase or decrease in size horizontally, and
the Label control will always remain a fixed distance from the top of the Button
control, as shown in Figure 49.
When the Anchor property is set to Bottom, Top, Left and Right, the control
will remain in the centre of the form. Play around with the Anchor property to
get a feel and understanding of it.
3.2.5.2 Docking
By using the Dock property, a control can be set to span one whole side of the
form. Using the Dock property attaches a control to the selected edge of the
form. The Fill dock option docks the control to all the sides of the form, and
causes it to fill up the entire form. Figure 50 shows how to modify the Dock
property of a control.
3.2.6 TextBoxes
In this section the TextBox control is introduced with the use of Label controls
and Button controls. The TextBox control is designed to receive input from the
user of the program.
TextBox
Run the program and enter some text into the TextBox control.
The text on the Button reflects the text entered into the TextBox, as shown in
Figure 54.
Table 15 contains the properties of TextBox controls that are frequently used.
The GroupBox and Panel controls have very similar functions. They are both
used to group controls together. The GroupBox control displays a frame around
the group of controls and can contain a caption in the top left corner. The
reason for grouping certain controls is to create order.
The GroupBox control cannot use scrollbars. If this is desired, a Panel control
should be used instead. The difference between a GroupBox control and a
Panel control is that a GroupBox control contains a caption and a Panel control
can have a scrollbar.
Figure 57 shows what a GroupBox control looks like with controls added to it,
and what a Panel control looks like with scrollbars.
Remember: containers need to be added first (the GroupBox control and/or the
Panel control), and only then may the other controls be placed within them.
These containers can be found in the Toolbox window, as previously described
(see Figure 58).
Note that these controls are found under the sub-division called Containers. In
order to add scrollbars to the Panel control, go to the Properties window and
set the AutoScroll property to true (see Figure 59).
CheckBox and RadioButton controls are state buttons. This means that they
have two states: true/false or on/off. There is a subtle but important difference
between a CheckBox and a RadioButton control. RadioButton controls are
generally grouped together and only one may be selected at a time. The
CheckBox control, on the other hand, is created to be ticked to indicate
selection, or to have the tick removed to indicate deselection. CheckBox
controls allow more than one option to be selected at any given time.
There are a few common CheckBox properties and events to note, as shown in
Table 17:
Create an application that looks like the one displayed in Figure 60.
Add a Label control (lblText) and two CheckBox controls (chkBold and
chkItalics).
Using the Xor operator in the example above avoids having to test whether a
style is already bold or italic. The exclusive OR operator (Xor) tests two
conditions and returns true only if one of the conditions is true. If both of the
conditions are true, then it returns false. If both conditions are false, it also
returns false.
3.2.9 MessageBoxes
The following is the syntax used to add an icon and a title to the simple
MessageBox:
AbortRetryIgnore
OK
OKCancel
RetryCancel
YesNo
YesNoCancel
Asterisk
Error
Exclamation
Hand
Information
None
Question
Stop
Warning
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
// Add System.Windows.Forms to be able to use DialogResult.
using System.Windows.Forms;
namespace MessageBoxProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// If Yes is selected.
if (result == DialogResult.Yes)
{
lblResult.Text = "You pressed: Yes";
}
// If No is selected.
else if (result == DialogResult.No)
{
Figures 62, 63 and 64 show the various stages of this example program:
Figure 64 – Form after the Yes button was selected from the
MessageBox
When the user presses Cancel, the label will display ‘You pressed: Cancel’ and
when No is pressed, the application will simply exit.
All events may be added by clicking on the Events button in the Properties
window (see Figure 65).
The Event Properties window should now look like Figure 66.
Keyboard events are generated when keys are pressed. These include
KeyPress, KeyDown and KeyUp. These are inherited from
System.Windows.Forms.Control.
Add the following code to the KeyPress, KeyDown and KeyUp event-handlers of
the form:
The PictureBox control is a control that allows the user to displays an image.
The whole source code document should look like the following:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PictureBoxDemo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Note that all the code is automatically generated except the Form1_Load
event. No other code is altered for this example. Merely add any
pictures/images to test the program above. Ensure that the name in the
FromFile() method matches the file in the bin\Debug folder. The SizeMode
property of the individual picture boxes may be altered. This places the image
either in the centre of the picture box or leaves it as normal. It may also be set
to AutoSize which adjusts the image to fit the picture box. Explore this option
to learn more. Also experiment with the option to change the background
colour.
It is, however, better to add any images to the project using the Solution
Explorer.
A dialog will open which is used to select images. This image will have to be
imported to the project first:
Click Import.
Use the file dialog to browse to the location of the image.
Select the image and click Open.
Select an image from the list of imported images and click OK.
This image will now be saved in the project’s Resources folder and is visible in
the Solution Explorer as show in Figure 72.
The selected image will now appear in pictureBox1. The image will, however,
be too big for the PictureBox control. To prevent this from happening, change
the PictureBox control’s SizeMode property.
The image will now automatically resize and the whole image will be visible.
The next thing that needs to be possible is to change the image while the
application is running. The image has now been added to the project; however,
there is an easier way to do this via the Solution Explorer:
The image will now appear in the Resources folder in the Solution Explorer and
can be used in the application. The path provided to the image can be relative
or absolute. The relative path is from where the application’s .exe file is to
The image can be loaded with the following syntax in the Form_Load event-
handler:
pictureBox1.Image = Image.FromFile("../../Resources/visualStudio.png");
pictureBox2.Image = Image.FromFile("../../Resources/fluid.png");
pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;
pictureBox2.SizeMode = PictureBoxSizeMode.AutoSize;
3.3.2 Menus
The form will look like Figure 74 once the MenuStrip has been added.
On line 3 the MainMenu is simply added to the Form. The order in which the
MenuItems are added to the form is also the order in which they will be
displayed.
3.3.2.4 Separators
To add a separator line in a menu, simply enter a hyphen (‘-’) where it says
‘Type Here’ or use the Design View. Separators are used to create logical and
ordered menu layouts as shown in Figures 76 and 77.
Try holding down <Alt> and then pressing the access shortcut keys to see
how they function.
3.3.4.1 ListBox
The main purpose of a ListBox control is to list multiple items in one list. Some
common ListBox properties are shown in Table 20.
Enter the code below into the FormLoad event of the application:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Many values can be added to the ListBox by clicking on the Items property in
the Property window. See Table 21 for a list of methods for the ListBox control.
In order to add one item at a time, the following code can be used:
lstDemo.Items.Add("Jaguar");
int numItems = 0;
3.3.4.2 CheckedListBox
The CheckedListBox is very similar to the ListBox control. When an item is
checked or unchecked, an ItemCheck event occurs. The CheckedItems
property specifies a collection of the currently selected items.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Figure 82 – CheckListBox
Add the following line to the previous code to add individual items:
chkLstDemo.Items.Add("Lexus");
int numItems = 0;
3.3.4.3 ComboBox
A ComboBox can be thought of as a drop-down box. Only one value is visible
until such time as the drop-down button is clicked, and the user may then
select any one of the values displayed. Once the selection has been made, the
other values are hidden again. Only one value can be selected at a time from
the ComboBox control. Figure 85 shows a typical ComboBox control.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
cmbDemo.Items.AddRange(new object[]
{
"Golf",
"Mazda",
"Hyundai",
"VW",
"Honda",
"BMW",
"Mercedes"
});
}
}
}
The ComboBox control has a Text property that can be changed when the
application is first run. If no text is entered into the Text property, the
ComboBox will be left blank. When the arrow on the right-hand side of the
ComboBox is clicked, the items will appear. In order to add items to the
ComboBox at design time, select the Items property from the Properties
window. Click on the ‘…’ button and a separate window appears where the
items are added one at a time.
When the application is run and a different item is selected from the list, the
SelectedIndexChanged event will be triggered. Another property that may be
of great use is the MaxDropDownItems property. It is used to specify the
maximum number of items that may be displayed when the arrow is clicked on
the right hand side of the ComboBox.
int numItems = 0;
Dialogs are special windows designed to interact with the user, to provide
information and/or obtain information from them. In C#, Dialogs are derived
from the CommonDialog class. There are many different DialogBox controls.
They are found in the Toolbox window under the Dialogs section and are
listed below:
ColorDialog
FolderBrowserDialog
FontDialog
OpenFileDialog
SaveFileDialog
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Threading.Tasks;
9 using System.Windows.Forms;
10
11 namespace ColorDialogAppl
12 {
13 public partial class Form1 : Form
14 {
15 public Form1()
16 {
17 InitializeComponent();
18 }
19
20 private void btnChange_Click(object sender, EventArgs e)
21 {
22 if (colorDialog1.ShowDialog() == DialogResult.OK)
23 {
24 // Sets the background colour.
25 this.BackColor = colorDialog1.Color;
26 }
27 }
28 }
29 }
Take note of the reference made to the Colour Dialog. Whilst Dialogs can be
added to the form, remember to add the ShowDialog() method manually as
shown on line 22. The ColorDialog control is used in this example to change
the background colour. Explore the effect of placing different Dialogs on the
form.
using System;
using System.Collections.Generic;
using System.Componentmodel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MDIExample
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComp();
}
void InitializeComp()
{
// ChildForm:
this.Text = "Child Form";
this.Size = new System.Drawing.Size(150, 150);
In addition to showing how MDI works, this example also illustrates how
modifying form properties in the source code modifies how a program
functions at runtime.
If the value is less than zero, then StringA (the first string) is less than
StringB (the second string).
If the value is zero, then StringA is equal to StringB.
If the value is greater than zero, then StringA is greater than StringB.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace CompareExample
8 {
The ternary operator is used in the above example to determine which string
should be used for the result.
namespace CompareOrdinalExample
{
class Program
{
static void Main(string[] args)
{
string str1 = "ABCD";
string str2 = "abcd";
string str3;
int result;
Console.WriteLine();
Console.WriteLine("Compare the numeric values of the " +
"corresponding Char objects in each " +
"string.");
Console.WriteLine("str1 = '{0}', str2 = '{1}'", str1, str2);
Compare the numeric values of the corresponding Char objects in each string.
str1 = 'ABCD', str2 = 'abcd'
String 'ABCD' is
less than
String 'abcd'.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConcatExample
{
class Program
{
static void Main(string[] args)
{
string fName = "Suhayl ";
string lName = "Asmal";
// Concatenate the two strings.
Console.WriteLine("Hello {0}!", string.Concat(fName, lName));
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace CopyExample
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 string strA = "abc";
14 string strB = "xyz";
15
16 Console.WriteLine("strA BEFORE copying = '{0}'", strA);
17 Console.WriteLine("strB BEFORE copying = '{0}'", strB);
18 Console.WriteLine("Copying...");
19 // Copying strA and storing it in strB.
20 strB = string.Copy(strA);
21 Console.WriteLine("strA AFTER copying = '{0}'", strA);
22 Console.WriteLine("strB AFTER copying = '{0}'", strB);
23 Console.ReadLine();
24 }
25 }
26 }
The method on line 20 makes a copy of a strA. Here strB, which was previously
‘xyz’ on line 14, is now replaced with the copied string ‘abc’. This is then
displayed on line 22, and illustrates the difference clearly.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace EqualsExample
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 string strA = "abcd";
14 string strB = "abcd";
15 Object obj = null;
16
17 Console.WriteLine();
18 Console.WriteLine("**strA's value is '{0}'.", strA);
19 Console.WriteLine();
20
21 obj = strB;
22 Console.WriteLine("The value of Object obj is '{0}'",
23 strA.Equals(obj));
24 Console.WriteLine();
25 Console.WriteLine("String.Equals(String)");
26 Console.WriteLine("The value of String strB is '{0}'."
27 , strB);
28 Console.WriteLine("Is strA equal to strB?: {0}",
29 String.Equals(strA, strB));
30 Console.WriteLine();
31 Console.WriteLine("String.Equals(String, String)");
32 Console.WriteLine("Is strA equal to strB?: {0}",
33 strA.Equals(strB));
34 Console.ReadLine();
35 }
36 }
37 }
String.Equals(String)
The value of String strB is 'abcd'.
Is strA equal to strB?: True
String.Equals(String, String)
Is strA equal to strB?: True
The Equals() method evaluates to either true or false. On lines 22 and 23, the
object obj is displayed and then checked against strA to see whether or not
they are equal. It should be found that the result is true. strA and strB are
then compared on line 29 and 30. This result is also true.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace FormatExample
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 string result;
14 string strA = "String A";
15 string formatString = "{0, 10}";
16
17 // Format specified string.
18 result = string.Format(formatString, strA);
19 Console.WriteLine("string.Format({0}, {1}) = [{2}]",
20 formatString, strA, result);
21 Console.ReadLine();
22 }
23 }
24 }
object arg0 is the first object to write using format. In this case it is equal to
"{0, 10}".
object arg1 is the second object to write using format. In this case it is equal
to strA which is equal to "String A".
object arg2 is the third object to write using format. In this case it is equal to
the result on line 18.
This method returns a string value after a certain format string has been
applied to it. This is the result:
This method is generally only used when creating large numbers of long,
complicated strings which have a high probability of being the same.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace InternExample
{
class Program
{
static void Main(string[] args)
{
string sA = "MySummer";
string sB = sBuilder.ToString();
string sC = string.Intern(sB);
sA == 'MySummer'
sB == 'MySummer'
sC == 'MySummer'
Is sB the same reference as sA?: False
Is sC the same reference as sB?: True
namespace IsInternedExample
{
class Program
{
public static void Main()
{
// String strA is known at compile-time, and is automatically
// interned.
String strA = "abcd";
// Call the public method Run, sending two parameters: int and
// string.
Run(1, strA);
Run(2, strB);
Console.ReadLine();
}
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace JoinExample
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 String[] val = { "MintCrisp", "Tempo", "KitKat", "BarOne" };
14 String sep = ", ";
15 String result;
16 Console.WriteLine("sep = '{0}'", sep);
17 Console.WriteLine("val[] = {{'{0}' '{1}' '{2}' '{3}'}}",
18 val[0], val[1], val[2], val[3]);
19 result = String.Join(sep, val, 1, 3);
20 Console.WriteLine("String.Join(sep, val, 1, 3) = '{0}'",
21 result);
22 Console.ReadLine();
23 }
24 }
25 }
Note that none of these methods change the original string. Instead, they
return a changed version of the original string. If the original value needs to be
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StringInstanceMethods
{
class Program
{
static void Main(string[] args)
{
// Declare a string to test the methods with .
String testString = "This is a test string";
// Pause.
Console.ReadLine();
}
}
}
Many other methods (and overloads) in the String class have not been shown
in the above example. Try using Visual Studio’s code completion feature to
learn more about them:
The Length property returns the number of characters in a string value. In the
following example, the Length property is used to get the number of characters
in str. The result is a value of 5.
int count;
string str = "hey";
count = str.Length;
Console.WriteLine("str.Length: {0}", count);
The String indexer returns a character within the string at a specific location.
In the example below, the indexer extracts the second character from a zero-
based count on str. The result is the character ‘t’.
char count;
string str = "hey there";
count = str[4];
Console.WriteLine("str[4]: {0}", count);
namespace StringBuilderExample
{
class Program
{
static void Main(string[] args)
{
// Declare an instance of the StringBuilder class.
StringBuilder sb = new StringBuilder();
// Declare an array of strings.
string[] wordArray = { "This", "string", "has", "been",
"constructed", "using", "a",
"StringBuilder"};
for (int loop = 0; loop < wordArray.Length; loop++)
{
sb.Append(wordArray[loop]);
if (loop != wordArray.Length – 1)
{
sb.Append(" ");
}
else
{
sb.Append(".");
}
}
Note that the Append() method can be used to append values of almost any
type to the StringBuilder, not just other string values.
StringBuilder myStringBuilder;
int count;
myStringBuilder.Capacity: 16
StringBuilder myStringBuilder;
int count;
myStringBuilder = new StringBuilder("It's summer time");
count = myStringBuilder.Length;
Console.WriteLine("myStringBuilder.Length: {0}", count);
myStringBuilder.Length: 16
StringBuilder myStringBuilder;
int count;
myStringBuilder = new StringBuilder("It's summer time");
count = myStringBuilder.MaxCapacity;
Console.WriteLine("myStringBuilder.MaxCapacity: {0}", count);
myStringBuilder.MaxCapacity: 2147483647
StringBuilder myStringBuilder;
char count;
myStringBuilder = new StringBuilder("It's summer time");
count = myStringBuilder[3];
Console.WriteLine("myStringBuilder[3]: {0}", count);
myStringBuilder[3]: s
Table 23 lists all the format strings available. Note that the format string is not
case-sensitive, e.g. {0:c} and {0:C} will produce the same result. The
following shows the general syntax used for formatting a string:
{0: specifier}
namespace FormatExample2
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("I can write numbers like this: " +
" string + number + number");
Console.WriteLine("Or I can write them like.." +
" {0} {1} {2}", 1, 2, 3);
// Format specifier.
Console.WriteLine("Number : {0, -12:E2}, {1, 10:N}", 5000000,
1000000);
/* A currency : This setting is affected by the regional settings
of your machine, and you may see $ instead of R. */
Console.WriteLine("Money : {0:c}", 1970);
// To Hex:
Console.WriteLine("Hex : {0:x}", 1970);
// Exponent:
Console.WriteLine("Exponent: {0:00e+0}", 27893.23464345);
// Phone number:
Console.WriteLine("Phone number: {0:(###)###-####}", 1123456789);
Console.ReadLine();
}
}
}
The two main functions are to match and then replace a string. Match checks if
the pattern is found within the string and if it is, it returns an object which can
be tested. Replace changes the string according to a user-defined pattern. It
finds a certain pattern within a string and then replaces it with that specified
pattern.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions; // Needed for Regular Expressions
namespace RegularExpressionsExample
{
class Program
{
static void Main(string[] args)
{
// Pattern for an email address.
string pattern = "[A-Za-z0-9]*@[A-Za-z0-9]*[.][A-Za-z0-9]*";
NOTE In this section, methods listed with(s) in front of the method name
are static methods.
namespace ArrayListExample
{
class Program
{
static void Main(string[] args)
{
// Declare an ArrayList.
ArrayList al = new ArrayList();
// Add some random values of varying types.
al.Add("Hello");
al.Add(true);
al.Add(new Object());
al.Add(5);
Hello
True
System.Object
5
======================
726643700
822959691
2075067574
The BitArray class can be used to store bits (a bit being either a 1 or a 0) in an
array-like structure. Each element can be set to true (1) or false (0). In many
ways, it is like an array of bool variables. Table 27 shows the methods used
when working with a BitArray.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections; // Required for BitArray
namespace BitArrayExample
{
class Program
{
static void Main(string[] args)
Console.WriteLine();
Console.ReadLine();
}
}
}
The result is :
True
True
True
True
True
True
True
True
False
False
False
False
False
False
False
False
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections; // Required for HashTable
namespace HashTableExample
{
class Program
{
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
ht.Add("Pick'nPay", "765-4321");
ht.Add("Spar", "678-9101");
ht.Add("Checkers", "123-4567");
Checkers: 678-9101
A Queue is a First In-First Out (FIFO) collection. It is just like standing in a line
when going to the bank. The first person in the line should be the first person
to get service. A Queue is a good collection to use when a limited resource is
being managed. For example, a programmer may want to send messages to a
resource. This resource can only handle one message at a time. A message
queue could be used to store messages in the order they are received. Table
29 shows the methods used when working with the Queue class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections; // Required for Queue
namespace QueueExample
{
class Program
{
static void Main(string[] args)
{
Queue q = new Queue();
q.Enqueue("message 1");
q.Enqueue("message 2");
The example below shows how values can be stored and retrieved from a
SortedList:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections; //Required for ArrayList Collections
namespace SortedListExample
{
class Program
{
static void Main(string[] args)
{
SortedList sl = new SortedList();
sl.Add("Pick'nPay", "765-4321");
sl.Add("Spar", "678-9101");
sl.Add("Checkers", "123-4567");
Pick'nPay: 765-4321
Spar: 678-9101
Checkers: 123-4567
678-9101
The significant methods of the Stack class are shown in Table 31:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections; // Required for ArrayList Collections
namespace StackExample
{
class Program
{
static void Main(string[] args)
{
// Use the Stack collection.
Stack st = new Stack();
st.Push("animal 1");
st.Push("animal 2");
st.Push("animal 3");
st.Push("animal 4");
Collection classes have many methods in common. This makes them more
predictable and easier to use in applications because they are consistent with
each other. This consistency is enforced by the interfaces they implement. The
standard interfaces which can be implemented when creating custom collection
types are shown in Table 32.
The interfaces the collection implements are dependent upon the type of the
collection. For example, a Hashtable implements IDictionary, stating that it
implements key/value semantics.
True/False
Multiple choice
Multiple response
5. Which three of the following image formats are not supported by .NET?
a. .jpg
b. .cs
c. .bmp
d. .ico
e. .ic
f. .bitmap
NOTE
When planning and creating the project, remember to follow the
guidelines as set out in the introduction to this guide.
Blackjack is a popular card game where the aim of the game is to get a higher
score than the dealer without exceeding a value of 21.
Programming
o Commands to start a new game or quit the program must be
represented by command buttons on the main form.
o Use the card images provided to represent the current hand.
Remember that the dealer only shows one card until the player’s
turn has finished.
o Keep track of a player’s wins, losses and ties. This information
should be displayed on a scoreboard.
o The cards must be dealt randomly from the deck of 52 cards.
HINT: give each of the cards a number from 0 – 51 and store
information about each of them (i.e. which image to use, scoring
value).
The Ace is a special case; store it with a value of 0. When an
Ace is dealt, determine at the time whether it should have a
value of 11 or a value of 1.
Ensure that the same card is not dealt twice in one hand. A
good way to do this is to store the cards dealt to the player
and the dealer in separate collections, and then check any
card being dealt against those collections. The Contains
method can be useful here.
o Commands to either Hit or Stay must be present. These should be
disabled when not in use.
o A Deal command, which will be used to start a new hand, must be
present. This button should be disabled when a hand is being
played, and then enabled once the hand is over.
o The current total of the player’s cards must be displayed at all
times.
o Once a hand is complete, the result must be displayed to the user,
whether it is a win, a loss, or a tie.
Student: Instructor:
Date Submitted: Date Marked:
General comments
Total: 100
Using Visual Studio, create an editor window that will function in a similar
fashion to Microsoft Word.
The editor window is a platform on which text files can be opened and edited
as the user pleases.
Images will be provided. You may use these images or create your own.
Programming:
o Commands to create a new text document, to open an existing
document, exit the application, or display information about the
application must be represented by a menu item at the top of the
editor.
o There must be functionality to create a new document or open an
existing one in the form of button controls.
o Use an OpenFileDialog to open existing text documents only.
o All text in the RichTextBox control will be lost when opening an
existing text document. Inform the user of this by using a
MessageBox.
o Use the images provided (or those that you have created) to
illustrate each button control’s purpose.
o A further five button controls must be added to accommodate
changes that may occur to the document’s text. These will be
changes such as background colour, font colour, bold, italic and
underline.
o Use a ColorDialog to change the background and font colour.
Student: Instructor:
Date Submitted: Date Marked:
General comments
Total: 100
line */
lines</summary> */
CONSTANTS
const double PI = 3.14; Const MAX_STUDENTS As Integer = 25 // May be initialized in a constructor
// Can be set to a const or a variable. May be ' Can set to a const or var; may be initialized in final double PI = 3.14;
// initialized in a constructor. ‘ a constructor
readonly int MAX_HEIGHT = 9; ReadOnly MIN_DIAMETER As Single = 4.93
ARRAYS
int[] nums = {1, 2, 3}; Dim nums As Integer() = {1, 2, 3} int nums[] = {1, 2, 3}; or int[] nums = {1,
for (int i = 0; i < nums.Length; i++) Dim i As Integer 2, 3};
Console.WriteLine(nums[i]); For i = 0 To Nums.Length for (int i = 0; i < nums.length; i++)
Console.WriteLine(nums[i]) System.out.println(nums[i]);
string[] names = new string[5]; Next String names[] = new String[5];
names[0] = "David"; Dim names(5) As String names[0] = "David";
names(0) = "David" float twoD[][] = new float[rows][cols];
float[,] twoD = new float[rows, cols]; Dim twoD(rows-1, cols-1) As Single twoD[2][0] = 4.5;
twoD[2,0] = 4.5f; twoD(2, 0) = 4.5 int[][] jagged = new int[5][];
int[][] jagged = new int[3][] { Dim jagged()() As Integer = { _ jagged[0] = new int[5];
new int[5], new int[2], new int[3] }; New Integer(4) {}, New Integer(1) {}, _ jagged[1] = new int[2];
jagged[0][4] = 5; New Integer(2) {} } jagged[2] = new int[3];
jagged(0)(4) = 5 jagged[0][4] = 5;
EXCEPTION HANDLING
Exception up = new Exception("Something is really Throw an exception // Must be in a method that is declared to throw
wrong."); Dim ex As New _ // this exception
throw ex; Exception("Something is really wrong.") Exception ex = new Exception("Something is really
Throw ex wrong.");
try ' Catch an exception throw ex;
{ Try try {
y = 0; y = 0 y = 0;
x = 10 / y; x = 10 / y x = 10 / y;
} ' Argument and When is optional } catch (Exception ex) {
catch (Exception ex) // Variable "ex" is Catch ex As Exception When y = 0 System.out.println(ex.getMessage());
{ // optional } finally {
Console.WriteLine(ex.Message); Console.WriteLine(ex.Message) // Code that always gets executed
} Finally }
finally Beep()
{ End Try
// Code that always gets executed
}
NAMESPACES
namespace CTIGroup.CTI.HO Namespace CTIGroup.Cti.HO package CTIGroup.CTI.HO;
{ ...
... End Namespace
} ' or
or Namespace CTIGroup
namespace CTIGroup Namespace CTI
{ Namespace HO
namespace CTI ... // Import single class
{ End Namespace import CTIGroup.CTI.HO.Table;
namespace HO End Namespace // Import all classes
{ End Namespace import CTIGroup.CTI.HO.*;
... Imports CTIGroup.CTI.HO
}
}
// Import all class. Can't import single class.
using CTIGroup.CTI.HO;
CONSOLE I/O
Console.Write("What's your name? "); Console.Write("What's your name? ") System.out.print("What's your name? ");
string name = Console.ReadLine(); Dim name As String = Console.ReadLine() string name = in.readline();
Console.Write("How old are you? "); Console.Write("How old are you? ") System.out.print("How old are you? ");
int age = Convert.ToInt32(Console.ReadLine()); Dim age As Integer = Val(Console.ReadLine()) int age = Integer.parseInt(in.readline());
Console.WriteLine(name + " is " + age + Console.WriteLine("{0} is {1} years old.", name, _ System.out.println(name + “ is “ + age + “ years
" years old."); age) old”);
' or
int c = Console.Read(); // Read single char Console.WriteLine(name & " is " & age & _ int c;
Console.WriteLine(c); // Prints 65 if user " years old.") c = in.read();
// enters "A" System.out.println(in);
Dim c As Integer
c = Console.Read() ' Read single char
Console.WriteLine(c) ' Prints 65 if user enters
‘ "A"
// Free the object Console.WriteLine(hero.Name) ' Prints WormWoman hero = null; // Free the object
hero = null ; hero = Nothing ' Free the object if (hero == null)
If hero Is Nothing Then _ {
if (hero == null) hero = New SuperHero hero = new SuperHero();
{ Dim obj As Object = New SuperHero }
hero = new SuperHero(); If TypeOf obj Is SuperHero Then _
} Console.WriteLine("Is a SuperHero object.") Object obj = new SuperHero();
End If System.out.println("object's type: " +
Object obj = new SuperHero(); obj.getClass().toString());
Console.WriteLine("object's type: " + Using reader As StreamReader = _
obj.GetType().ToString()); File.OpenText("test.txt") if (obj instanceof SuperHero)
{
if (obj is SuperHero) Dim line As String = reader.ReadLine() System.out.println("Is a SuperHero object.");
{ While Not line Is Nothing }
Console.WriteLine(line)
Console.WriteLine("Is a SuperHero object."); line = reader.ReadLine()
} End While
End Using
STRUCTS
struct StudentRecord Structure StudentRecord No structs in Java.
{ Public name As String
public string name; Public gpa As Single
public float gpa;
Public Sub New(ByVal name As String, _
public StudentRecord(string name, float gpa) ByVal gpa As Single)
{ Me.name = name
this.name = name; Me.gpa = gpa
this.gpa = gpa; End Sub
} End Structure
} Dim stu As StudentRecord = _
StudentRecord stu = new StudentRecord("Bob", 3.5f); New StudentRecord("Bob", 3.5)
StudentRecord stu2 = stu;
Dim stu2 As StudentRecord = stu
stu2.name = "Sue";
Console.WriteLine(stu.name); // Prints Bob stu2.name = "Sue"
Console.WriteLine(stu2.name); // Prints Sue Console.WriteLine(stu.name) ' Prints Bob
Console.WriteLine(stu2.name) ' Prints Sue
// Character stream writing ' Write out to text file // Character stream writing
StreamWriter writer = File.CreateText("myfile.txt"); Dim writer As StreamWriter = FileWriter writer = new FileWriter("myfile.txt");
writer.WriteLine("Out to file."); File.CreateText("myfile.txt") writer.write("Out to file.\n");
writer.Close(); writer.WriteLine("Out to file.") writer.close();
writer.Close()
// Character stream reading // Character stream reading
StreamReader reader = File.OpenText("myfile.txt"); ' Read all lines from text file FileReader reader = new FileReader("myfile.txt");
string line = reader.ReadLine(); Dim reader As StreamReader = BufferedReader br = new BufferedReader(reader);
while (line != null) File.OpenText("myfile.txt") String line = br.readLine();
{ Dim line As String = reader.ReadLine() while (line != null)
Console.WriteLine(line); While Not line Is Nothing {
line = reader.ReadLine(); Console.WriteLine(line) System.out.println(line);
} line = reader.ReadLine() line = br.readLine();
reader.Close(); End While }
reader.Close() reader.close();
// Binary stream writing
BinaryWriter out = new ' Write out to binary file // Binary stream writing
BinaryWriter(File.OpenWrite("myfile.dat")); Dim str As String = "Text data" FileOutputStream out = new
out.Write("Text data"); Dim num As Integer = 123 FileOutputStream("myfile.dat");
out.Write(123); Dim binWriter As New out.write("Text data".getBytes());
out.Close(); BinaryWriter(File.OpenWrite("myfile.dat")) out.write(123);
binWriter.Write(str) out.close();
// Binary stream reading binWriter.Write(num)
BinaryReader in = new binWriter.Close() // Binary stream reading
BinaryReader(File.OpenRead("myfile.dat")); FileInputStream in = new
string s = in.ReadString(); ' Read from binary file FileInputStream("myfile.dat");
int num = in.ReadInt32(); Dim binReader As New byte buff[] = new byte[9];
in.Close(); BinaryReader(File.OpenRead("myfile.dat")) // Read first 9 bytes into buff
str = binReader.ReadString() in.read(buff, 0, 9);
num = binReader.ReadInt32() String s = new String(buff);
binReader.Close() int num = in.read(); // Next is 123
in.close();
Term Description
Textbooks
Dorman, S., 2010. Sams teach yourself Visual C# 2010 in 24 hours: Complete
Starter Kit. Boston: Pearson Education, Inc.
Deitel, PJ & Deitel, HM. 2009. C# 2008 for programmers. Third Edition.
Boston: Pearson Education, Inc.
Websites
Tutorialspoint: http://www.tutorialspoint.com/csharp/
Students please note that unless all of your exercises have been signed off by an instructor
you will not be allowed to book for the exam.
1 _______________ 3 _______________
1 ______________
2.4.4 Exceptions and exception 2.6.7 Structs and conversions Unit 2 – Test your knowledge
handling Exercises Revision questions Multiple response
(Complete exercise on paper) (Complete exercise on paper) (Complete exercise on paper)
3.2.13 Introduction to Windows 3.4.6 String manipulation and Unit 3 – Test your knowledge
forms Revision questions regular expressions Revision Multiple choice
(Complete exercise on paper) questions (Complete exercise on paper)
(Complete exercise on paper)
1 _______________ 1 _______________
1 _______________
2 _______________ 2 _______________
2 _______________
3 _______________ 3 _______________
3 _______________
3.3.7 More advanced controls
Exercises 3.5.8 Collections Exercises 4 _______________
(Complete exercise on paper) (Complete exercise on paper)
Unit 3 – Test your knowledge
Multiple response
1 _______________ 1 _______________ (Complete exercise on paper)
2 _______________ 1 _______________
3 _______________ 2 _______________
3 _______________ 1 _______________
4 _______________ 2 _______________
5 _______________ 3 _______________
6 _______________ 4 _______________
7 _______________
Note: Please ensure that you have Google Chrome browser installed on your
device before viewing the link.
CTI is part of Pearson, the world’s leading learning company. Pearson is the corporate owner, not a registered
provider nor conferrer of qualifications in South Africa. CTI Education Group (Pty) Ltd. is registered with
the Department of Higher Education and Training as a private higher education institution under the
Higher Education Act, 101, of 1997. Registration Certificate number: 2004/HE07/004. www.cti.ac.za.