This chapter is taken from book "
Beginning C#
Object-Oriented Programming " by Dan Clark published for Apress.
In the previous chapter,
you looked at how the .NET Framework was developed and how programs execute
under the framework. That chapter introduced you to the Visual Studio IDE, and
you gained some familiarity with working in it. You are now ready to start
coding! This chapter is the first of a series that will introduce you to how
classes are created and used in C#. It covers the basics of creating and using
classes. You will create classes, add attributes and methods, and instantiate
object instances of the classes in client code.
After reading this chapter, you should be familiar with the following:
- How objects used in OOP depend on class
definition files.
- The important role encapsulation plays in
OOP.
- How to define the properties and methods
of a class.
- The purpose of class constructors.
- How to use instances of classes in client
code.
- The process of overloading class
constructors and methods.
- How to create and test class definition
files with Visual Studio.
Introducing Objects and Classes
In OOP, you use objects in your programs to encapsulate the data associated with
the entities with which the program is working. For example, a human resources
application needs to work with employees. Employees have attributes associated
with them that need to be tracked. You may be interested in such things as the
employee names, addresses, departments, and so on. Although you track the same
attributes for all employees, each employee has unique values for these
attributes. In the human resources application, an Employee object obtains and
modifies the attributes associated with an employee. In OOP, the attributes of
an object are referred to as properties.
Along with the properties of the employees, the human resource application also
needs an established set of behaviors exposed by the Employee object. For
example, one employee behavior of interest to the human resources department is
the ability to request time off. In OOP, objects expose behaviors through
methods. The Employee object contains a RequestTimeOff method that encapsulates
the implementation code.
The properties and methods of the objects used in OOP are defined through
classes. A class is a blueprint that defines the attributes and behaviors of the
objects that are created as instances of the class. If you have completed the
proper analysis and design of the application, you should be able to refer to
the UML design documentation to determine which classes need to be constructed
and what properties and methods these classes will contain. The UML class
diagram contains the initial information you need to construct the classes of
the system.
To demonstrate the construction of a class using C#, you will look at the code
for a simple Employee class. The Employee class will have properties and methods
that encapsulate and work with employee data as part of a fictitious human
resources application.
Defining Classes
Let's walk through the source code needed to create a class definition. The
first line of code defines the code block as a class definition using the
keyword Class followed by the name of the class. The body of the class
definition is enclosed by an open and closing curly bracket. The code block is
structured like this:
class
Employee
{
}
Creating Class Properties
After defining the starting and ending point of the class code block, the next
step is to define the instance variables (often referred to as fields) contained
in the class. These variables hold the data that an instance of your class will
manipulate. The Private keyword ensures that these instance variables can be
manipulated only by the code inside the class. Here are the instance variable
definitions:
private
int _empID;
private
string _loginName;
private
string _password;
private
string _department;
private
string _name;
When a user of the class (client code) needs to query or set the value of these
instance variables, public properties are exposed to them. Inside the property
block of code are a Get block and a Set block. The Get block returns the value
of the private instance variable to the user of the class. This code provides a
readable property. The Set block provides a write-enabled property; it passes a
value sent in by the client code to the corresponding private instance variable.
Here is an example of a property block:
public
string Name
{
get { return
_name; }
set { _name = value;
}
}
There may be times when you want to restrict access to a property so that client
code can read the property value but not change it. By eliminating the Set block
inside the Property block, you create a read-only property. The following code
shows how to make the EmployeeID property read-only:
public
int EmployeeID
{
get { return
_empID; }
}
Note The private and public keywords affect the scope of the code. For
more information about scoping, see Appendix A.
Newcomers to OOP often ask why it's necessary to go through so much work to get
and set properties. Couldn't you just create public instance variables that the
user could read and write to directly? The answer lies in one of the fundamental
tenets of OOP: data encapsulation. Data encapsulation means that the client code
does not have direct access to the data. When working with the data, the client
code must use clearly defined properties and methods accessed through an
instance of the class. The following are some of the benefits of encapsulating
the data in this way:
- Preventing unauthorized access to the
data.
- Ensuring data integrity through error
checking.
- Creating read-only or write-only
properties.
- Isolating users of the class from changes
in the implementation code.
For example, you could check to make sure the
password is at least six characters long via the following code:
public
string Password
{
get { return
_password; }
set
{
if (value.Length
>= 6)
{
_password = value;
}
else
{
throw new
Exception("Password
must be at least 6 characters");
}
}
}
Creating Class Methods
Class methods define the behaviors of the class. For example, the following
defines a method for the Employee class that verifies employee logins:
public
void Login(string
loginName, string password)
{
if (loginName ==
"Jones" & password == "mj")
{
_empID = 1;
Department = "HR";
Name = "Mary Jones";
}
else if (loginName
== "Smith" & password ==
"js")
{
_empID = 2;
Department = "IS";
Name = "Jerry Smith";
}
else
{
throw new
Exception("Login
incorrect.");
}
}
When client code calls the Login method of the class, the login name and
password are passed into the method (these are called input parameters). The
parameters are checked. If they match a current employee, the instance of the
class is populated with attributes of the employee. If the login name and
password do not match a current employee, an exception is passed back to the
client code.
Note Exception handling is an important part of application processing.
For more information about exceptions, see Appendix B.
In the previous method, a value is not returned to the client code. This is
indicated by the void keyword. Sometimes the method returns a value back to the
client calling code (called an output parameter). The following AddEmployee
method is another method of the Employee class. It's called when an employee
needs to be added to the database, and it returns the newly assigned employee ID
to the client. The method also populates the object instance of the Employee
class with the attributes of the newly added employee.
public
int AddEmployee(string
loginName, string password,
string
department, string name)
{
//Data normally saved to database.
_empID = 3;
LoginName = loginName;
Password = password;
Department = department;
Name = name;
return EmployeeID;
}
ACTIVITY 6-1. CREATING THE EMPLOYEE CLASS
In this activity, you will become familiar with the following:
- Creating a C# class definition file using
Visual Studio.
- Creating and using an instance of the
class from client code.
Note If you have not already done so,
download the starter files from the source code area of the Apress web site (www.apress.com).
Defining the Employee Class
To create the Employee class, follow these steps:
- Start Visual Studio. Select File -> Open
-> Project.
- Navigate to the Activity6_1Starter folder,
click the Act6_1.sln file, and click Open. When the project opens, it will
contain a login form. You will use this form later to test the Employee
class you create.
- Select Project -> Add Class. In the Add
New Item dialog box, rename the class file to Employee.cs, and then click
Open. Visual Studio adds the Employee.cs file to the project and adds the
following class definition code to the file:
class
Employee
{
}
- Enter the following code between the
opening and closing brackets to add the private instance variables to the
class body in the definition file:
private
int _empID;
private
string _loginName;
private
string _password;
private
int _securityLevel;
- Next, add the following public properties
to access the private instance variables defined in step 4:
public
int EmployeeID
{
get { return
_empID; }
}
public
string LoginName
{
get { return
_loginName; }
set { _loginName =
value; }
}
public
string Password
{
get { return
_password; }
set { _password =
value; }
}
public
int SecurityLevel
{
get { return
_securityLevel; }
}
- After the properties, add the following
Login method to the class definition:
public
void Login(string
loginName, string password)
{
LoginName = loginName;
Password = password;
//Data nomally retrieved from database.
//Hard coded for demo only.
if (loginName ==
"Smith" & password ==
"js")
{
_empID = 1;
_securityLevel = 2;
}
else if
(loginName == "Jones" & password ==
"mj")
{
_empID = 2;
_securityLevel = 4;
}
else
{
throw new
Exception("Login
incorrect.");
}
}
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
Testing the Employee Class
To test the Employee class, follow these steps:
- Open frmLogin in the code editor and
locate the btnLogin click event code.
Tip Double-clicking the Login button in the form designer will also
bring up the event code in the code editor.\
- In the body of the btnLogin click event,
declare and instantiate a variable of type Employee called oEmployee:
Employee oEmployee = new
Employee();
- Next, call the Login method of the
oEmployee object, passing in the values of the login name and the password
from the text boxes on the form:
oEmployee.Login(txtName.Text,txtPassword.Text);
- After calling the Login method, show a
message box stating the user's security level, which is retrieved by reading
the SecurityLevel property of the oEmployee object:
MessageBox.Show("Your
security level is " + oEmployee.SecurityLevel);
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
- Select Debug -> Start to run the project.
Test the login form by entering a login name of Smith and a password of js.
You should get a message indicating a security level of 2. Try entering your
name and a password of pass. You should get a message indicating the login
failed.
- After testing the login procedure, close
the form; this will stop the debugger.
Using Constructors
In OOP, you use constructors to perform any processing that needs to occur when
an object instance of the class becomes instantiated. For example, you could
initialize properties of the object instance or establish a database connection.
The class constructor method is named the same as the class. When an object
instance of a class is instantiated by client code, the constructor method is
executed. The following constructor is used in the Employee class to initialize
the properties of an object instance of the Employee class. An employee ID is
passed in to the constructor to retrieve the values from data storage, like so:
public Employee(int
empID)
{
//Retrieval of data hardcoded for demo
if
(empID == 1)
{
_empID = 1;
LoginName = "Smith";
Password = "js";
Department = "IT";
Name = "Jerry Smith";
}
else
if (empID == 2)
{
_empID = 2;
LoginName = "Jones";
Password = "mj";
Department = "HR";
Name = "Mary Jones";
}
else
{
throw
new Exception("Invalid
EmployeeID");
}
}
Overloading Methods
The ability to overload methods is a useful feature of OOP languages. You
overload methods in a class by defining multiple methods that have the same name
but contain different signatures. A method signature is a combination of the
name of the method and its parameter type list. If you change the parameter type
list, you create a different method signature. For example, the parameter type
lists can contain a different number of parameters or different parameter types.
The compiler will determine which method to execute by examining the parameter
type list passed in by the client.
Note Changing how a parameter is passed (in other words, from byVal to
byRef) does not change the method signature. Altering the return type of the
method also does not create a unique method signature. For a more detailed
discussion of method signatures and passing arguments, refer to Appendix A.
Suppose you want to provide two methods of the Employee class that will allow
you to add an employee to the database. The first method assigns a username and
password to the employee when the employee is added. The second method adds the
employee information but defers the assignment of username and password until
later. You can easily accomplish this by overloading the AddEmployee method of
the Employee class, as the following code demonstrates:
public int
AddEmployee(string loginName,
string password,string
department, string name)
{
//Data normally saved to database.
_empID = 3;
LoginName = loginName;
Password = password;
Department = department;
Name = name;
return EmployeeID;
}
public
int AddEmployee(string
department, string name)
{
//Data normally saved to database.
_empID = 3;
Department = department;
Name = name;
return EmployeeID;
}
Because the parameter type list of the first method (string, string) differs
from the parameter type list of the second method (string, string, string,
string), the compiler can determine which method to invoke. A common technique
in OOP is to overload the constructor of the class. For example, when an
instance of the Employee class is created, one constructor could be used for new
employees and another could be used for current employees by passing in the
employee ID when the class instance is instantiated by the client. The following
code shows the overloading of a class constructor:
public Employee()
{
_empID = -1;
}
public
Employee(int empID)
{
//Retrieval of data hard coded for demo
if
(empID == 1)
{
_empID = 1;
LoginName =
"Smith";
Password = "js";
Department = "IT";
Name = "Jerry Smith";
}
else
if (empID == 2)
{
_empID = 2;
LoginName =
"Jones";
Password = "mj";
Department = "HR";
Name = "Mary Jones";
}
else
{
throw
new Exception("Invalid
EmployeeID");
}
}
ACTIVITY 6-2. CREATING CONSTRUCTORS AND OVERLOADING METHODS
In this activity, you will become familiar with the following:
- Creating and overloading the class
constructor method.
- Using overloaded constructors of a class
from client code.
- Overloading a method of a class.
- Using overloaded methods of a class from
client code.
Creating and Overloading Class Constructors
To create and overload class constructors, follow these steps:
- Start Visual Studio. Select File --> Open --> Project.
- Navigate to the Activity6_2Starter folder,
click the Act6_2.sln file, and then click Open. When the project opens, it
will contain a frmEmployeeInfo form that you will use to test the Employee
class. The project also includes the Employee.cs file, which contains the
Employee class definition code.
- Open Employee.cs in the code editor and
examine the code. The class contains several properties pertaining to
employees that need to be maintained.
- After the property declaration code, add
the following private method to the class. This method simulates the
generation of a new employee ID.
private
int GetNextID()
{
//simulates the retrieval of next
//available id from database
return 100;
}
- Create a default class constructor, and
add code that calls the GetNextID method and assigns the return value to the
private instance variable _empID:
public Employee()
{
_empID = GetNextID();
}
- Overload the default constructor method by
adding a second constructor method that takes an integer parameter of empID,
like so:
public Employee(int
empID)
{
//Constructor for existing employee
}
- Add the following code to the overloaded
constructor, which simulates extracting the employee data from a database
and assigns the data to the instance properties of the class:
//Simulates retrieval from database
if
(empID == 1)
{
_empID = empID;
LoginName =
"smith";
PassWord = "js";
SSN = 123456789;
Department = "IS";
}
else
if (empID == 2)
{
_empID = empID;
LoginName =
"jones";
PassWord = "mj";
SSN = 987654321;
Department = "HR";
}
else
{
throw new
Exception("Invalid
Employee ID");
}
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
Testing the Employee Class Constructors
To test the Employee class constructors, follow these steps:
- Open the EmployeeInfoForm in the form
editor and double click the New Employee button to bring up the click event
code in the code editor.
- In the Click Event method body, declare
and instantiate a variable of type Employee called oEmployee:
Employee oEmployee = new
Employee();
- Next, update the EmployeeID text box with
the employee ID, disable the EmployeeID text box, and clear the remaining
textboxes:
Employee oEmployee = new Employee()
txtEmpID.Text = oEmployee.EmpID.ToString();
txtEmpID.Enabled = false;
txtLoginName.Text = "";
txtPassword.Text = "";
txtSSN.Text = "";
txtDepartment.Text = "";
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
- Open the EmployeeInfoForm in the form
editor and double click the Existing Employee button to bring up the click
event code in the code editor.
- In the Click Event method body, declare
and instantiate a variable of type Employee called oEmployee. Retrieve the
employee ID from the txtEmpID text box and pass it as an argument in the
constructor. The int.Parse method converts the text to an integer data type:
Employee oEmployee = new
Employee(int.Parse(txtEmpID.Text));
- Next, disable the Employee ID textbox and
fill in the remaining text boxes with the values of the Employee object's
properties:
txtEmpID.Enabled =
false;
txtLoginName.Text = oEmployee.LoginName;
txtPassword.Text = oEmployee.PassWord;
txtSSN.Text = oEmployee.SSN.ToString();
txtDepartment.Text = oEmployee.Department;
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
- Select Debug -> Start to run the project
and test the code.
- When the EmployeeInfo form is displayed,
click the New Employee button. You should see that a new employee ID has
been generated in the Employee ID textbox.
- Click the Reset button to clear and enable
the Employee ID text box.
- Enter a value of 1 for the employee ID and
click the Get Existing Employee button. The information for the employee is
displayed on the form.
- After testing the constructors, close the
form, which will stop the debugger.
Overloading a Class Method
To overload a class method, follow these steps:
- Open the Employee.cs code in the code
editor.
- Add the following Update method to the
Employee class. This method simulates the updating of the employee security
information to a database:
public
string Update(string
loginName, string password)
{
LoginName = loginName;
PassWord = password;
return
"Security info updated.";
}
- Add a second Update method to simulate the
updating of the employee human resources data to a database:
public
string Update(int
ssNumber, string department)
{
SSN = ssNumber;
Department = department;
return "HR
info updated.";
}
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
Testing the Overloaded Update Method
To test the overloaded Update method, follow these steps:
- Open the EmployeeInfo Form in the Form
editor and double click the Update SI button. You are presented with the
click event code in the Code Editor window.
- In the Click Event method, declare and
instantiate a variable of type Employee called oEmployee. Retrieve the
employee ID from the txtEmpID text box and pass it as an argument in the
constructor:
Employee oEmployee = new
Employee(int.Parse(txtEmpID.Text));
- Next, call the Update method, passing the
values of the login name and password from the text boxes. Show the method
return message to the user in a message box:
MessageBox.Show(oEmployee.Update(txtLoginName.Text,
txtPassword.Text));
- Update the login name and password text
boxes with the property values of the Employee object:
txtLoginName.Text = oEmployee.LoginName;
txtPassword.Text = oEmployee.PassWord;
- Repeat this process to add similar code to
the Update HR button Click Event method to simulate updating the human
resources information.
Add the following code to the Click Event method:
Employee oEmployee = new
Employee(int.Parse(txtEmpID.Text));
MessageBox.Show(oEmployee.Update(int.Parse(txtSSN.Text),
txtDepartment.Text));
txtSSN.Text
= oEmployee.SSN.ToString();
txtDepartment.Text
= oEmployee.Department;
- Select Build -> Build Solution. Make sure
there are no build errors in the Error List window. If there are, fix them,
and then rebuild.
- Select Debug -> Start to run the project
and test the code.
- Enter a value of 1 for the employee ID and
click the Get Existing Employee button.
- Change the values for the security
information and click the Update button.
- Change the values for the human resources
information and click the Update button.
- You should see that the correct Update
method is called in accordance with the parameters passed in to it. After
testing the Update method, close the form.
Summary
This chapter gave you a firm foundation in creating and using classes in C#
code. Now that you are comfortable constructing and using classes, you are ready
to look at implementing some of the more advanced features of OOP. In the next
chapter, you will concentrate on how inheritance and polymorphism are
implemented in C# code. As an object-oriented programmer, it is important for
you to become familiar with these concepts and learn how to implement them in
your programs.