COURSE SYLLABUS Department of Computer Studies College of Sciences Norton University Course Title: Advanced Programming Methodology in C# Lecturer: CHHIENG Sokha Course Description: This course, students learn the fundamental skills that are required to design and develop object-oriented applications for the Microsoft Windows by using Microsoft Visual C# .NET and the Microsoft Visual Studio .NET development environment. This course provides an alternative entry point for less experienced programmers who are not familiar with object-oriented design and programming with Windows.
Course Prerequisite: Experience with object-oriented programming and concepts are not required for this course. Before attending this course, students must have competency in the following areas:
Familiarity and comfort with basic operating system functions such as file manipulation.
Understanding of the basics of structured programming, including concepts such as flow control, variables and parameters, and function calls.
Consultation Hours: Half an hour before the start of the classes Course Outline: For the duration of 16 weeks, the course is outlined as follows: Number of Weeks
2
2
Topic Introduction Chapter 1: Getting Started Introduction to .NET and the .NET Framework Exploring Visual Studio .NET Creating a Windows Application Project After completing this Chapter, students will be able to: Identify components of the .NET platform and the .NET Framework by their function. Explore the Visual Studio development environment. Create a basic application based on Microsoft Windows. Chapter 2: Understanding C# Language Fundamentals Understanding the Fundamentals of a C# Program Using C# Predefined Types Writing Expressions I|Page
Creating Conditional Statements Creating Iteration Statements After completing this Chapter, students will be able to: Understand the fundamentals of a C# program. Use C# predefined types. Write expressions. Create conditional statements. Create iteration statements. Chapter 3: Creating Objects in C# Defining a Class Declaring Methods Using Constructors Using Static Class Members
3
2
4
1
After completing this Chapter, students will be able to: Define a class. Declare methods. Use constructors. Use static class members. Chapter 4: Implementing Object-Oriented Programming Techniques in C# Designing Objects Using Inheritance Using Polymorphism After completing this Chapter, students will be able to: Encapsulate information in an object. Create an object that inherits functionality from another object. Implement polymorphism to use abstract classes. Chapter 5: Programming with C# Using Arrays Using Collections Using Interfaces Using Exception Handling Using Delegates and Events After completing this Chapter, students will be able to: Create and use arrays. Use classes in the System.Collections namespace. Use the ArrayList class. Use interfaces. Handle exceptions. Create and call a delegate. Use delegates to handle events. Chapter 6: Building .NET-based Applications with C# Examining the .NET Framework Class Library Overriding Methods from System.Object Formatting Strings and Numbers Using Streams and Files After completing this Chapter, students will be able to: II | P a g e
Identify a namespace in the .NET Framework class library by its function. Override and implement the ToString method. Format strings, currency, and date values. Read and write both binary and text files. Chapter 7: Creating Windows-based Applications Creating the Main Menu Creating and Using Common Dialog Boxes Creating and Using Custom Dialog Boxes Creating and Using Toolbars Creating the Status Bar Creating and Using Combo Boxes After completing this Chapter, students will be able to: Create the main menu. Create and use common dialog boxes. Create and use custom dialog boxes. Create and use toolbars. Create the status bar. Create and use combo boxes.
2
First Final Examination COURSE REQUIREMENTS AND GRADING SYSTEM Homework and Presentation, and Mid Term exam Course Project (or Assignment) Class Participation (Attendance, Discipline, and Involvement) Final exam
20% 15% 5% 60%
Total Passing grade
100% 50%
DATE TO REMEMBER Project proposal deadline Midterm exam Deadline of the project defense Final Exam
in 3 weeks 12th week 14th week 17th week
REFERENCES - MCAD-Microsoft Certified Application Developer (Course 2609A) - Microsoft Visual C# 2008 Step by Step - Microsoft MSDN [http://msdn.microsoft.com] - C# Tutorial [http://www.csharp-station.com]
III | P a g e
Norton University| DCS, Y2
Introduction: Welcome to C#
Welcome to C#
INTRODUCTION
WELCOME TO C# After completing this chapter, you will be able to:
Use the Visual Studio 2008 programming environment. Create a C# console application. Use namespaces. Create a C# Windows Forms application.
Microsoft Visual C# is Microsoft's powerful, component-oriented language. C# plays an important role in the architecture of the Microsoft .NET Framework, and some people have drawn comparisons to the role that C played in the development of UNIX. If you already know a language such as C, C++, or Java, you'll find the syntax of C# reassuringly familiar because it uses the same curly brackets to delimit blocks of code. However, if you are used to programming in other languages, you should soon be able to pick up the syntax and feel of C#; you just need to learn to put the curly brackets and semi-colons in the right place. Hopefully this is just the book to help you!
Lecturer: Chhieng Sokha |Nguon Bunsour
2
Welcome to C#
BEGINNING PROGRAMMING WITH THE VISUAL STUDIO 2008 ENVIRONMENT Visual Studio 2008 is a tool-rich programming environment containing all the functionality you'll need to create large or small C# projects. You can even create projects that seamlessly combine modules from different languages. In the first exercise, you'll start the Visual Studio 2008 programming environment and learn how to create a console application. Create a console application in Visual Studio 2008 1. In Microsoft Windows, click the Start button, point to All Programs, and then point to Microsoft Visual Studio 2008. 2. Click the Microsoft Visual Studio 2008 icon. Visual Studio 2008 starts. NOTE If this is the first time that you have run Visual Studio 2008, you might see a dialog box prompting you to choose your default development environment settings. Visual Studio 2008 can tailor itself according your preferred development language. The various dialog boxes and tools in the integrated development environment (IDE) will have their default selections set for the language you choose. Select Visual C# Development Settings from the list, and then click the Start Visual Studio button. After a short delay, the Visual Studio 2008 IDE appears.
3. On the File menu, point to New, and then click Project. The New Project dialog box opens. This dialog box allows you to create a new project using various templates, such as Windows Lecturer: Chhieng Sokha |Nguon Bunsour
3
Welcome to C# Application, Class Library, and Console Application, that specify the type of application you want to create. NOTE The actual templates available depend on the version of Visual Studio 2008 you are using. It is also possible to define new project templates, but that is beyond the scope of this book.
4. In the Templates pane, click the Console Application icon. 5. In the Location field, type C:\Documents and Settings\YourName\My Documents\Microsoft Press\ Replace the text YourName in this path with your Windows user name. To save a bit of space throughout the rest of this book, we will simply refer to the path “C:\Documents and Settings\YourName\My Documents” as your “\My Documents” folder. NOTE If the folder you specify does not exist, Visual Studio 2008 creates it for you.
6. In the Name field, type Types. 7. Ensure that the Create Directory for Solution check box is checked and then click OK. The new project opens. The menu bar at the top of the screen provides access to the features you'll use in the programming environment. You can use the keyboard or the mouse to access the menus and commands exactly as you can in all Windows-based programs. The toolbar is located beneath the menu bar and provides button shortcuts to run the most frequently used commands. The Code and Text Editor window occupying the main part of the IDE displays the contents of source files. In a multi-file project, each source file has its own tab labeled with the name of the source file. You can click the tab once to bring the named source file to the foreground in the Code and Text Editor window. The Solution Explorer displays the names of the files associated with the project, among other items. You can also double-click a file name in the Solution Explorer to bring that source file to the foreground in the Code and Text Editor window. Lecturer: Chhieng Sokha |Nguon Bunsour
4
Welcome to C#
Before writing the code, examine the files listed in the Solution Explorer, which Visual Studio 2008 has created as part of your project:
Solution 'Types' This is the top-level solution file, of which there is one per application. If you use Windows Explorer to look at your \My Documents\ Microsoft Press, you'll see that the actual name of this file is TextHello.sln. Each solution file contains references to one or more project files.
Types This is the C# project file. Each project file references one or more files containing the source code and other items for the project. All the source code in a single project must be written in the same programming language. In Windows Explorer, this file is actually called Types.csproj, and it is stored in your My Documents\ Microsoft Press.
Properties
This is a folder in the Typesproject. If you expand it, you will see that it contains a file called AssemblyInfo.cs. AssemblyInfo.cs is a special file that you can use to add attributes to a program, Lecturer: Chhieng Sokha |Nguon Bunsour
5
Welcome to C# such as the name of the author, the date the program was written, and so on. There are additional attributes that you can use to modify the way in which the program will run. These attributes are outside the scope of this book.
References This is a folder that contains references to compiled code that your application can use. When code is compiled, it is converted into an assembly and given a unique name. Developers use assemblies to package up useful bits of code that they have written for distribution to other developers that might want to use them in their applications. Many of the features that you will be using when writing applications using this book will make use of assemblies provided by Microsoft with Visual Studio 2008.
Program.cs This is a C# source file, and is the one displayed in the Code and Text Editor window when the project is first created. You will write your code in this file. It contains some code that Visual Studio 2008 provides automatically, which you will examine shortly.
WRITING YOUR FIRST PROGRAM The Program.cs file defines a class called Program that contains a method called Main. All methods must be defined inside a class. The Main method is special—it designates the program's entry point. It must be a static method. (Methods are discussed in Chapter 3, “Writing Methods and Applying Scope.” Static methods are discussed in Chapter 7, “Creating and Managing Classes and Objects.” The Main method is discussed in Chapter 11, “Understanding Parameter Arrays.”) IMPORTANT C# is a case-sensitive language. You must spell Main with a capital M.
In the following exercises, you'll write the code to display the message Hello World in the console; you'll build and run your Hello World console application; you'll learn how namespaces are used to partition code elements.
Write the code using IntelliSense technology 1. In the Code and Text Editor window displaying the Program.cs file, place the cursor in the Main method after the opening brace, and type Console. As you type the letter C at the start of the word Console an IntelliSense list appears. This list contains all of the valid C# keywords and data types that are valid in this context. You can either continue typing, or scroll through the list and double-click the Console item with the mouse. Alternatively, after you have typed Con, the Intellisense list will automatically home in on the Console item and you can press the Tab, Enter, or Spacebar key to select it. Main should look like this: static void Main(string[] args) { Console }
Lecturer: Chhieng Sokha |Nguon Bunsour
6
Welcome to C# NOTE Console is a built-in class that contains the methods for displaying messages on the screen and getting input from the keyboard.
2. Type a period immediately after Console. Another IntelliSense list appears, displaying the methods, properties, and fi elds of the Console class. 3. Scroll down through the list, select WriteLine, and then press Enter. Alternatively, you can continue typing the characters W, r, i, t, e, L until WriteLine is selected, and then press Enter. The IntelliSense list closes, and the word WriteLine is added to the source fi le. Main should now look like this: static void Main(string[] args) { Console.WriteLine } 4. Type an opening parenthesis , (. Another IntelliSense tip appears. This tip displays the parameters that the WriteLine method can take. In fact, WriteLine is an overloaded method, meaning that the Console class contains more than one method named WriteLine—it actually provides 19 different versions of this method. Each version of the WriteLine method can be used to output different types of data. (Chapter 3 describes overloaded methods in more detail.) Main should now look like this: static void Main(string[] args) { Console.WriteLine( } Tip You can click the up and down arrows in the tip to scroll through the different overloads of WriteLine.
5. Type a closing parenthesis, ) followed by a semicolon, ;. Main should now look like this: static void Main(string[] args) { Console.WriteLine(); } 6. Move the cursor, and type the string “Hello World”, including the quotation marks, between the left and right parentheses following the WriteLine method. Main should now look like this: static void Main(string[] args) { Console.WriteLine(“Hello World”); }
Lecturer: Chhieng Sokha |Nguon Bunsour
7
Welcome to C# Tip Get into the habit of typing matched character pairs, such as ( and ) and { and }, before fi lling in their contents. It’s easy to forget the closing character if you wait until after you’ve entered the contents.
IntelliSense Icons When you type a period after the name of a class, IntelliSense displays the name of every member of that class. To the left of each member name is an icon that depicts the type of member. Common icons and their types include the following: Icon
Meaning Namespace Public method Public property Public class Structure Interface Event Delegate Assembly
Note You will frequently see lines of code containing two forward slashes followed by ordinary text. These are comments. They are ignored by the compiler but are very useful for developers because they help document what a program is actually doing. For example:
Console.ReadLine(); // Wait for the user to press the Enter key
The compiler will skip all text from the two slashes to the end of the line. You can also add multiline comments that start with a sequence (*/), which could be many lines lower down. You are actively encouraged to document your code with as many meaningful comments as necessary.
Lecturer: Chhieng Sokha |Nguon Bunsour
8
Norton University| DCS, Y2
Chapter 1: Getting Started
Contents Lesson 1: Introduction to .NET and the .NET Framework (10) Lesson 2: Exploring Visual Studio .NET (Go chapter 7) Lesson 3: Creating a Windows Application Project (Go chapter 7)
Chapter 1: Getting Started
Introduction
In this lesson, a multimedia presentation introduces the concepts that are fundamental to your knowledge of the .NET platform and the .NET Framework.
Lesson objectives
After completing this lesson, you will be able to: Identify the components of the .NET platform and the .NET Framework by their functions. Explain the function of the NET Framework class library and the common language runtime. This lesson includes the following topics and activities: What Is the .NET Platform? Multimedia: Introduction to .NET What Is the .NET Framework? How the .NET Framework Works Multimedia: Introduction to the .NET Framework
Lesson agenda
Lecturer: Chhieng Sokha |Nguon Bunsour
10
Chapter 1: Getting Started
Introduction
The .NET platform provides several core technologies and services that simplify the development of Web-based applications.
.NET platformcomponents
Developer tools Microsoft Visual Studio .NET and the .NET Framework supply a complete solution for developers. Visual Studio .NET provides the development environment for building applications on the .NET Framework. The development environment provides tools that simplify the creation, deployment, and ongoing evolution of secure, scalable, highly available Web applications and XML Web services. Devices Devices are personal computers, laptops, workstations, phones, handheld computers, Tablet PCs, game consoles, and others. A smart device can access XML Web services and enable access to data regardless of the location, type, and number of devices in use. User experiences .NET experiences are applications that use XML Web services to allow users to access information across the Internet and from stand-alone applications in an integrated and efficient way. Servers The .NET Enterprise Server family accelerates the integration of systems, applications, and partners by supporting XML Web services. Support of XML allows enterprises to build on earlier systems rather than replacing them. For example, Microsoft Host Integration Server provides simple access to mainframes and Microsoft BizTalk® Server offers automatic conversions of existing data formats to and from XML. Tip For information about the .NET Enterprise Server family, see http://www.microsoft.com/net/products/servers.asp.
Lecturer: Chhieng Sokha |Nguon Bunsour
11
Chapter 1: Getting Started XML Web services By using XML Web services, applications can share data and invoke capabilities from other applications without regard to how those applications were built, what operating system or platform they run on, and what devices are used to access them. .NET platform benefits The .NET platform provides several benefits for developers, including: for developers Faster application development Developers can create applications by using one of many modern programming languages, greatly increasing the pool of available developer resources in addition to allowing developers the freedom to use the programming language that is most suitable for solving a specific problem. Greater reliability o The .NET platform takes advantage of the power of distributed computing. o The common language runtime provides for a managed execution environment, which eliminates memory leaks, access violations, and versioning problems. o The .NET Framework enforces type safety, explicit code sharing, and application isolation, guaranteeing that no application can affect or illegally call another. Based on Web standards The use of XML removes barriers to data sharing and software integration. The Simple Object Access Protocol, an XML-based messaging technology standardized by the World Wide Web Consortium (W3C), specifies all the necessary rules for using XML Web services, integrating them into applications and communicating between them. o .NET has database access capabilities, allowing developers to bring open database connectivity (ODBC)-compliant data stores into their application architecture.
Lecturer: Chhieng Sokha |Nguon Bunsour
12
Chapter 1: Getting Started
Introduction
The .NET Framework provides the foundation for building and running .NET-based applications. The .NET Framework consists of two components, the common language runtime and the .NET Framework class library, which run on an operating system. Any language that conforms to the common language specification (CLS) can run on the common language runtime. In the .NET Framework, Microsoft provides support for Microsoft Visual Basic®, Microsoft Visual C++®, Microsoft Visual C#™ (pronounced C sharp), and Microsoft JScript®. Third parties can provide additional languages. Note Currently, the .NET Framework is built to run on the Microsoft Win32® operating systems.
The common language runtime
The common language runtime manages the execution of code and provides services to simplify the development process. The common language runtime provides a robust and secure execution environment, support for multiple languages, and a managed environment where common services, such as garbage collection and security, are automatically provided.
The .NET Framework class library
The .NET Framework class library exposes features of the runtime and provides a library of classes that are accessed by all Web, Windows-based, and XML Web service applications. In addition to base classes, the .NET Framework class library includes: Element ADO.NET
ASP.NET
Lecturer: Chhieng Sokha |Nguon Bunsour
Description Microsoft ADO.NET is the next generation of Microsoft ActiveX® Data Objects (ADO) technology. ADO.NET provides improved support for the disconnected programming model. It also provides rich XML support. Microsoft ASP.NET is a programming framework that is built on the common language runtime. ASP.NET can be used on a server to build Web applications. ASP.NET Web Forms provide an easy and powerful way to build dynamic Web user interfaces
13
Chapter 1: Getting Started XML Web services
User interfaces
Lecturer: Chhieng Sokha |Nguon Bunsour
(UI). XML Web services are programmable Web components that can be shared among applications on the Internet or the intranet. The .NET Framework provides tools and classes for building, testing, and distributing XML Web services. The .NET Framework supports three types of user interfaces: o Web Forms, which work by using ASP.NET. o Windows Forms, which run on Win32 client computers. o Console applications.
14
Chapter 1: Getting Started
Introduction
The common language runtime is the foundation of the .NET Framework.
MSIL
When you compile an application in Visual Studio .NET, it is translated into the runtime’s common language, Microsoft Intermediate Language (MSIL). After the application is compiled, the runtime manages the execution of the application.
JIT compilation
The runtime includes a feature called just-in-time (JIT) compilation that translates the MSIL code into the machine language of the system on which the application will run. When a client device on the .NET platform launches the .NET-based application, it starts running in the machine language of the client system and can fully integrate and interact with other .NET-based applications and services regardless of the language in which it was developed.
Lecturer: Chhieng Sokha |Nguon Bunsour
15
Chapter 1: Getting Started
Overview Term
1. Match the following terms with the appropriate definition by drawing a line that connects the term and definition. Definition
XML Web services
A. Component that periodically checks for objects that are ready to be released from a computer’s memory.
Devices
B. CPU-independent set of instructions than can be efficiently turned into CPU-specific code.
.NET experiences
C. Programmable entity that provides a particular element of functionality, such as application logic and is accessible to any number of potentially disparate systems.
.NET Framework
D. Component that contains a collection of reusable types that you can use to develop applications.
.NET Framework class library
E. Programming model of the .NET platform for building, deploying, and running XML Web services and all types of applications—both desktop and Web-based.
Common language runtime
F. Refers to a hand held computer or mobile telephone that can use .NET-based applications.
Garbage collection
G. Component that manages the execution of code and provides services to make the development process easier.
MSIL
H. Services, .NET-based applications, and Web sites that rely on XML Web services to enhance the user experience.
Answers: XML Web services(….); Devices (….); .NET experiences(….); .NET Framework (….); .NET Framework class library (….);Common language runtime (….); Garbage collection (….); MSIL (….);
2. What must be installed on a client computer to run .NET-based applications? _____________________________________________________________ 3. Complete the following statement: When you create a project in Visual Studio .NET, are organized in a larger container called a
.
files
4. Complete the following statement: An provides starter files and a project structure and contains the basic project objects and the environment settings that you need to create the type of application that you want to build. 5. What is one advantage of programming by using the .NET Framework versus using a traditional development environment?
Lecturer: Chhieng Sokha |Nguon Bunsour
16
Norton University| DCS, Y2
Chapter 2: Understanding C# Language Fundamentals Contents Lesson 1: Understanding the Fundamentals of c# Programming (18) Lesson 2: Using C# Predefined Type (23) Lesson 3: Writing Expressions (31) Lesson 4: Creating Conditional Statements (34) Lesson 5: Creating Iteration Statements (37)
Chapter 2 : Understanding C# Language Fundamentals
Introduction
This module introduces you to the basic syntax and structure of the C# language. It describes C# data types, including variables and constants, describes the Microsoft® .NET common type system, introduces conditional and iterative statements, and explains how to create user-defined enumeration types. Understanding the syntax of the language is fundamental to writing code in C#.
Objective
After completing this module, you will be able to:
Understand the fundamentals of a C# program.
Use C# predefined types.
Write expressions.
Create condi onal statements.
Create itera on statements.
Lecturer: Chhieng Sokha |Nguon Bunsour
18
Chapter 2 : Understanding C# Language Fundamentals
Introduction
This lesson describes the structure of a C# program. This information is provided as a resource for developers who have no experience with a C-style language.
Lesson Objective
Lesson agenda
After completing this lesson, you will be able to:
Iden fy C# statements.
Use braces to group statements.
Include comments in code.
This lesson includes the following topics:
What Is the Structure of a C# Program?
How to Format Code in C#
Lecturer: Chhieng Sokha |Nguon Bunsour
19
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Before you write your first lines of code in C#, it is helpful to understand the structure of the language.
Definition
The structure of a programming language specifies the elements that you must include in your application and defines how to organize those elements so that the compiler understands your code.
Example of C# Structure
The following code shows the basic structure of a C# application: using System; class HelloWorld { static void Main() { Console.WriteLine ("Hello, World"); } } The elements and organizing principles that are shown in the preceding six lines of code are briefly described line by line in the following sections.
The using keyword The using keyword refers to resources in the Microsoft .NET Framework class library. Typically, you insert this keyword at the beginning of the program file, usually several times, to reference various resources. The System namespace
System is a namespace that provides access to all of the system functionality upon which your application is built.
Class
Programming in C#, or any object-oriented language, consists of writing classes, which are used to create objects. In the preceding code example, the class is named HelloWorld.
Lecturer: Chhieng Sokha |Nguon Bunsour
20
Chapter 2 : Understanding C# Language Fundamentals The Main method
Methods describe the behavior of a class. In the third line, static void Main is a global method that tells the compiler where to begin execution of the application. Every C# application must include a Main method in one of the classes.
Statements
Statements are instructions that are completed to perform actions in C# applications. Statements are separated by a semicolon to enable the compiler to distinguish between them. Some languages place one statement on one line. In C#, you can include multiple statements on one line, or one statement on multiple lines. It is good practice to write one statement per line; although, for the purpose of readability, you may want to break a long statement into several lines.
Braces
Braces, { and }, are used to identify the beginning and end of blocks of code in your application. Braces are used to group statements together. Every opening brace must have one matching closing brace. In the example, the braces following “class HelloWorld” enclose the items that are in the HelloWorld class. The braces following “Main” are used to enclose the statements that are in the Main method. Microsoft Visual Studio® .NET provides several visual cues that help to ensure that your braces are correctly matched. When you type a closing brace, the enclosing element is briefly shown in bold. Also, the document outline indicators to the left show the extent of a group of statements.
Note You do not need to add a semicolon after braces because the braces themselves indicate the end of a group of statements, implying that the statements within the braces are complete and separate blocks of code.
Lecturer: Chhieng Sokha |Nguon Bunsour
21
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Formatting is another element of program design that helps you to organize your code. You are encouraged to use formatting conventions to improve the structure and readability of your code.
Example
(In slide)
Indentation
Indentation indicates that a statement is within an enclosing statement. Statements that are in the same block of statements should all be indented to the same level. This is an important convention that improves the readability of your code. Although indenting is not a requirement, or enforced by the compiler, it is a recommended best practice.
Case sensitivity
C# is case sensitive, which means that the compiler distinguishes between uppercase and lowercase characters. For example, the words “code,” “Code,” and “CODE” are differentiated in your application; you cannot substitute one for the other.
White space
White space is ignored by the compiler. Therefore, you can use spaces to improve the readability and formatting of your code. The only exception is that the compiler does not ignore spaces between quotation marks.
Comments
You can include single-line comments in your application by inserting a double slash (//) followed by your comment. Alternately, if your comment is lengthy and spans multiple lines, you can use slash asterisk (/*) to indicate the beginning of a comment and asterisk slash (*/) to indicate the end of your comments. The following example of a multiple line comment includes an asterisk at the beginning of each line. These asterisks are optional and you can include them to make your comment easier to identify.
Multiple-line comment example
/* * Multiple line comment * This example code shows how to format multiple line comments in C# */
Lecturer: Chhieng Sokha |Nguon Bunsour
22
Chapter 2 : Understanding C# Language Fundamentals
Introduction
This lesson introduces the basic syntax of the C# language and the .NET common type system, including how to use types, variables, constants, enumerations, and strings. When you write any application, you must represent data in some way. This process fundamentally depends upon working with types.
Lesson objectives
Lesson agenda
After completing this lesson, you will be able to:
Declare and ini alize variables.
Create and use strings.
Create and use constants.
Create and use enumerated types.
Convert between types.
This lesson includes the following topics and activity:
What Are Predefined Types?
How to Declare and Ini alize Variables
How to Declare and Ini alize Strings
How to Create and Use Constants
How to Create and Use Enumera on Types
How to Convert Between Types
Prac ce: Using C# Types
Lecturer: Chhieng Sokha |Nguon Bunsour
23
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Whenever your application must store data temporarily for use during execution, you store that data in a variable. You can think of variables as storage boxes. These boxes come in different sizes and shapes, called types, which provide storage for various kinds of data. For example, the type of variable that is used to store a number is different than one that is used to store a person’s name.
Definition
Predefined types are those that are supplied by the C# language and the .NET Framework. The following table lists the predefined types and describes the data that they are designed to store.
Predefined type
Definition
# Bytes 1
byte
Integer between 0 and 255
sbyte
Integer between -128 and 127
1
short
Integer between -32768 and 32767
2
ushort
Integer between 0 and 65535
2
int
Integer between -2147483648 and 2147483647
4
uint
Integer between 0 and 4294967295
4
long
Integer between -9223372036854775808 and
8
9223372036854775807 ulong
Integer between 0 and 18446744073709551615
8
bool
Boolean value: true or false
1
float
Single-precision floating point value (non-whole number)
4
Lecturer: Chhieng Sokha |Nguon Bunsour
24
Chapter 2 : Understanding C# Language Fundamentals double
Double-precision floating point value
8
decimal
Precise decimal value to 28 significant digits
12
object
Base type of all other types
char
Single Unicode character between 0 and 65535
string
An unlimited sequence of Unicode characters
N/A 2 N/A
Storing data
Suppose that you are writing an application that allows a user to purchase items over the Internet with a credit card. Your application must handle several pieces of information: the person’s name, the amount of the purchase, the credit card number, and the expiration date on the card. To represent this information in your application, you use different types.
Choosing a type
Let the data that you are representing determine your choice of type. For example, if something can be only true or false, a bool type is the obvious choice. A decimal type is a good choice for currency. When working with integers, an int type is the typical choice, unless there is a specific reason to choose another type. In addition to the predefined types that are supplied by the .NET Framework, you can define your own types to hold whatever data you choose.
Lecturer: Chhieng Sokha |Nguon Bunsour
25
Chapter 2 : Understanding C# Language Fundamentals
Introduction
A variable is a storage location for a particular type. For example, if your application must process a currency value, it requires a variable to hold that value. Before you can use a variable, you must declare it. By declaring a variable, you are actually reserving some storage space for that variable in memory. After declaring a variable, you must initialize it by assigning a value to it.
Naming variables
The following list identifies some best practices for naming your variables:
Assign meaningful names to your variables.
Use camel case. In camel case, the first le lowercase,
er of the iden
fier is
and the first letter of each subsequent word in the identifier is capitalized, such as newAccountBalance.
Do not use C# keywords.
Although C# is case sensitive, do not create variables that differ only by case.
Escape characters
Some characters cannot be specified by being placed in quotation marks—for example, a newline character, a beep, or a quotation mark character. To represent these characters, you must use escape characters, which are shown in the following table.
Escape sequence
Character name
Escape sequence
Character name
\'
Single quotation
\f
Form feed
\"
Double quotatio
\n
New line
\\
Backslash
\r
Carriage return
\0
Null
\t
Horizontal tab
\a
Alert
\v
Vertical tab
\b
Backspace
Lecturer: Chhieng Sokha |Nguon Bunsour
26
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Strings are one of the most commonly used types.
Definition
A string variable contains a sequence of alphanumeric characters that are used as input for calculations or searches. Note There is no limit to the number of characters that can make up a string.
Syntax
You declare a string the same way you declare any other variable, by assigning a type (string) and giving it a name.
Understanding Unicode
The .NET Framework uses Unicode UTF-16 (Unicode Transformation Format, 16-bit encoding form) to represent characters. C# also encodes characters by using the international Unicode Standard. The Unicode Standard is the current universal character encoding mechanism that is used to represent text in computer processing. The previous standard was ASCII. The Unicode Standard represents a significant improvement over ASCII because Unicode assigns a unique numeric value, called a code point, and a name to each character that is used in all the written languages of the world. ASCII defined only 128 characters, which meant that some languages could not be correctly displayed in a computer application. For example, the character “A” is represented by the code point “U+0041” and the name “LATIN CAPITAL LETTER A”. Values are available for over 65,000 characters, and there is room to support up to one million more. For more information, see The Unicode Standard at www.unicode.org.
Lecturer: Chhieng Sokha |Nguon Bunsour
27
Chapter 2 : Understanding C# Language Fundamentals
Introduction
A constant is a variable whose value remains constant. Constants are useful in situations where the value that you are using has meaning and is a fixed number, such as pi, the radius of the earth, or a tax rate.
Benefits
(In slide)
Syntax
(In slide)
Examples
(In slide)
Lecturer: Chhieng Sokha |Nguon Bunsour
28
Chapter 2 : Understanding C# Language Fundamentals
Introduction
An enumeration type specifies a group of named numeric constants. An enumeration type is a user-defined type, which means that you can create an enumeration type, declare variables of that type, and assign values to those variables. The purpose of an enumeration type is to represent constant values.
Benefits
In addition to providing all the advantages of constants, enumerations:
Syntax
Make your code easier to maintain by ensuring that your variables are assigned only anticipated values.
Allow you to assign easily identifiable names to the values, thereby making your code easier to read.
Make your code easier to type, because as you assign enumeration values,
Microsoft IntelliSense® displays a list of the possible values that you can use.
Allow you to specify a set of constant values and define a type that will accept values from only that set.
You create an enumeration type by using the enum keyword, assigning a name, and then listing the values that your enumeration can take. It is recommended that you use Pascal case for the type name and each enumeration member. In Pascal case, you capitalize the initial letter of each word in the identifier, such as ListOfThePlanets.
Lecturer: Chhieng Sokha |Nguon Bunsour
29
Chapter 2 : Understanding C# Language Fundamentals
Introduction
When designing applications, you often must convert data from one type to another. Conversion can be necessary when you perform operations on two types that are not the same.
Definitions
There are two types of conversions in the .NET Framework: implicit and explicit conversions.  An implicit conversion is a conversion that is automatically performed by the common language runtime on operations that are guaranteed to succeed without truncating information.  An explicit conversion is a conversion that requires you to explicitly ask the compiler to perform a conversion that otherwise could lose information or produce an error.
Implicit conversions
The following table shows the implicit type conversions that are supported in C#: From
To
sbyte
short, int, long, float, double, decimal
byte
short, ushort, int, uint, long, ulong, float, double, decimal
short
int, long, float, double, decimal
ushort
int, uint, long, ulong, float, double, decimal
int
long, float, double, decimal
uint
long, ulong, float, double, decimal
long, ulong
float, double, decimal
float
double
char
ushort, int, uint, long, ulong, float, double, decimal
Lecturer: Chhieng Sokha |Nguon Bunsour
30
Chapter 2 : Understanding C# Language Fundamentals
Introduction
This lesson explains how to use operators to create expressions.
Lesson objective
After completing this lesson, you will be able to use operators to create expressions.
Lesson agenda
This lesson includes the following topics and activity:
What Are Expressions and Operators?
How to Determine Operator Precedence
Practice: Using Operators
Lecturer: Chhieng Sokha |Nguon Bunsour
31
Chapter 2 : Understanding C# Language Fundamentals
Introduction
The purpose of writing an expression is to perform an action and return a value. For example, you can write an expression to perform a mathematical calculation, assign a value, or compare two values.
Definitions
An expression is a sequence of operators and operands. An operator is a concise symbol that indicates the action that you want to occur in your expression. An operand is the value on which an operation is performed. An operator is specifically designed to produce a new value from the value that is being operated on.
Types of operators
Some of the common types of operators that you can use in your C# applications include:
Increment and decrement: Used to increase or decrease a value by one.
Arithmetic: Used to perform arithmetic calculations like addition.
Relational. Used to define greater than, greater than or equal to, less than, and so on.
Equality: Used to state equal to, or not equal.
Conditional: Used to define and/or situations.
Assignment: Used to assign a value to a variable.
Lecturer: Chhieng Sokha |Nguon Bunsour
32
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Developers often create expressions that perform more than one calculation, comparison, or a combination of the two. In these situations, the precedence of the operators controls the order in which the expression is evaluated. If you want the operations performed in a different order; you must tell the compiler to evaluate the expression differently by using parentheses.
Evaluation order
The order in which operators are evaluated in an expression is shown in the following precedence table. Operator type
Operator
Multiplicative
*, /, %
Additive
+,-
Shift
<< , >>
Relational
< , > , <= , >= , is, as
Equality
== , !=
Logical
&,^,|
Conditional
&& , || , ?:
Assignment
= , *= , /= , %= , += , -= , <<=, >>= , &= , ^= , |=
For example, the plus operator + has a lower precedence than the multiplication operator, so a + b * c means multiply b and c, and then add the sum to a.
Lecturer: Chhieng Sokha |Nguon Bunsour
33
Chapter 2 : Understanding C# Language Fundamentals
Introduction
This lesson introduces you to conditional statements. You learn how and when to use if and switch statements.
Lesson objectives
Lesson agenda
After completing this lesson, you will be able to:
Use the if…else conditional statement to manage the flow of control in anapplication.
Use the switch conditional statement to manage the flow of control in an application.
This lesson includes the following topics and activity:
How and When to Use the if Statement
How and When to Use the switch Statement
Prac ce: Using Condi onal Statements
Lecturer: Chhieng Sokha |Nguon Bunsour
34
Chapter 2 : Understanding C# Language Fundamentals
Introduction
A conditional statement allows you to control the flow of your application by selecting the statement that is executed, based on the value of a Boolean expression. There are three variations to the conditional if statement, including: if, if else, and if else if. When the expression that is being evaluated is true, the code following the if statement is executed.
Lecturer: Chhieng Sokha |Nguon Bunsour
35
Chapter 2 : Understanding C# Language Fundamentals
Introduction
A switch statement selects the code to execute based upon the value of a test. However, a switch statement enables you to test for multiple values of an expression rather than just one condition. Switch statements are useful for selecting one branch of execution from a list of mutually-exclusive choices. Using switch statements makes your application more efficient and your code more readable than using multiple, nested if statements.
Syntax
A switch statement takes the form of a switch expression followed by a series of witch blocks, indicated by case labels. When the expression in the argument evaluates to one of the values in a particular case, the code immediately following that case executes. When no match occurs, a default condition is executed, if one is defined.
Break
You must include a break statement at the end of each switch block, or a compile error occurs. It is not possible to fall through from one switch block to the following switch block.
Lecturer: Chhieng Sokha |Nguon Bunsour
36
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Lesson objectives
Lesson agenda
C# provides several looping mechanisms, which enable you to execute a block of code repeatedly until a certain condition is met. In each case, a statement is executed until a Boolean expression returns true. By using these looping mechanisms, you can avoid typing the same line of code over and over. After completing this lesson, you will be able to:
Write a for loop.
Write a while loop.
Write a do loop.
This lesson includes the following topics and activity:
How to Use a for Loop
How to Use a while Loop
How to Use a do Loop
Prac ce: Using Itera on Statements
Lecturer: Chhieng Sokha |Nguon Bunsour
37
Chapter 2 : Understanding C# Language Fundamentals
Introduction
A for loop is used to execute a statement block a set number of times. A for loop is a commonly-used way of executing a block of statements several times. The for loop evaluates a given condition, and while the condition is true, it executes a block of statements. The for loop is called a pretest loop because the loop condition is evaluated before the loop statements are executed. If the loop condition tests false, the statements are not executed. You use a for loop when you know in advance the number of times that you want to repeat execution of your code statement.
Example
For example, suppose that you are designing an application to calculate the amount of money that you will have in your savings account after 10 years with a given starting balance, and you want to display the total that you will have at the end of each year. One way that you can write this code is to write a statement like balance *= interestRate in your code ten times, or you can simply write a for loop.
Lecturer: Chhieng Sokha |Nguon Bunsour
38
Chapter 2 : Understanding C# Language Fundamentals
Introduction
Similar to the for loop, the while loop is a pretest loop, which means that if the first test evaluates false, the statement does not execute. This is useful when you want to make sure that something is true before executing the code in your loop. You also use a while loop when you do not know exactly how many times you must execute the loop statements.
Syntax
The syntax for declaring a while loop is: while (true-condition) { statement-block }
Using the continue keyword
You can use the continue keyword to start the next loop iteration without executing any remaining statements.
The break keyword
You can also break out of a loop. When the break keyword is encountered, the loop is terminated, and execution continues at the statement that follows the loop statement.
Lecturer: Chhieng Sokha |Nguon Bunsour
39
Chapter 2 : Understanding C# Language Fundamentals
Introduction
In a do loop, the statement is executed, a condition is tested, and then the statement is executed again. This process repeats for as long as the condition tests true. This is known as a post-test loop. The do loop is useful when you want to execute a statement at least once.
Syntax
The syntax for a do loop is: do { statements } while (boolean-expression); Note The semicolon after the statement is required.
Lecturer: Chhieng Sokha |Nguon Bunsour
40
Chapter 2 : Understanding C# Language Fundamentals
Questions
1. What symbol indicates a single-line comment in your code? A. ------------------------------------------------------------------------------------2. True or false: You end a statement with a closing brace and a semicolon. A. ------------------------------------------------------------------------------------3. What is the largest value that can fit in a byte? A. ------------------------------------------------------------------------------------4. In the following expression, what is the value of y? Why? int x = 50; int y = ++x; A. ------------------------------------------------------------------------------------5. Fill in the blank: A ____________ statement allows you to control the flow the
of your application by selecting the statement that is executed, based on value of a Boolean expression.
6. True or False: The while loop is a pre-test loop. A. -------------------------------------------------------------------------------------
Lecturer: Chhieng Sokha |Nguon Bunsour
41
Norton University| DCS, Y2
Chapter 3: Creating Objects in C#
Contents Lesson 1: Defining a Class (44) Lesson 2: Declaring Methods (50) Lesson 3: Using Constructors (56) Lesson 4: Using Static Class Members (59)
Chapter 3: Creating Objects in C#
Introduction
This module introduces the fundamentals of object-oriented programming, including the concepts of objects, classes, and methods. It explains how to define classes and create objects, how to organize classes by using namespaces, and how to define, write, and call methods. Finally, it describes how to use constructors.
Objectives
After completing this module, you will be able to:
Define a class
Declare methods
Use constructors
Use static class members
Lecturer: Chhieng Sokha |Nguon Bunsour
43
Chapter 3: Creating Objects in C#
Introduction
This lesson discusses how to define classes, instantiate objects, access class members, and use namespaces to organize classes.
Lesson objectives
After completing this lesson, you will be able to: Define a class.
Lesson agenda
Create an object.
Use access modifiers to define the scope of class members.
Organize classes by using namespaces.
This lesson includes the following topics and activities: Multimedia: Introduction to Classes and Objects
What Are Classes and Objects?
What Are Value Types and Reference Types?
How to Define a Class and Create an Object
How to Organize Classes Using Namespaces
How to Define Accessibility and Scope
Practice: Defining Classes and Creating Objects
Lecturer: Chhieng Sokha |Nguon Bunsour
44
Chapter 3: Creating Objects in C#
Introduction
A class is the fundamental user-defined type in C#. You must define a class before you can create an object.
Definition
A class is essentially like a blueprint, from which you can create objects. A class defines the characteristics of an object, including properties that define the types of data that the object can contain and methods that describe the behavior of the object. These characteristics determine how other objects can access and work with the data that is contained in the object. An object is an instance of a class. If a class is like a blueprint, then an object is what is created from that blueprint. The class is the definition of an item; the object is the item. The blueprint for your house is like a class; the house that you live in is an object.
Lecturer: Chhieng Sokha |Nguon Bunsour
45
Chapter 3: Creating Objects in C#
Introduction
There are two kinds of types: value types and reference types. Most of the predefined types are value types. For example, an integer is a value type.
Value types
Value types directly contain their data. Therefore, each value type variable directly contains the value that it is assigned. Value types store themselves, and the data that they contain, in an area of memory called the stack. The stack is an area of memory that is used to store items in a lastin, first-out manner.
Reference types
Reference type variables contain a reference to their data. Objects are reference types. More than one reference type variable can reference the same object. Therefore, it is possible for operations on one reference type variable to affect other variables that refer to the same object, the same data. Reference types contain a reference to data that is allocated on the heap. The heap is an area of memory where objects are allocated.
Initializing a value type When you declare a value type variable, you must then initialize it before it can be used. To initialize a value type variable, you simply assign a value to that variable, as shown in the following example: int anInteger; anInteger = 42; The first line declares the value type variable int by naming it anInteger and the second line initializes the variable by assigning it a value of 42. Initializing a reference When you declare a reference type variable, you then initialize it by using the new type keyword. This keyword allocates some memory on the heap for your variable. For example, suppose that you have a class named Customer. Customer bestCustomer = new Customer(); The variable bestCustomer refers to an object of type Customer.
Lecturer: Chhieng Sokha |Nguon Bunsour
46
Chapter 3: Creating Objects in C#
Introduction
A class is like a blueprint that is used to create objects, in the same way that a blueprint for a house is used to create many individual houses.
Syntax
To define a class, you place the class keyword before the name of your class, and then you insert the class members between braces. [attributes] [access-modifiers] class identifier {class-body}
Pascal case
It is recommended that you use Pascal case for your class name, for example, MyClassName. Pascal case means that the initial letter of each word in the identifier is capitalized.
Example
The following example defines a new class, Customer, with three associated pieces of relevant informationâ&#x20AC;&#x201D;the customerâ&#x20AC;&#x2122;s name, the credit limit of the customer, and a customer ID. Although the Customer class is defined in the example, there are no Customer objects yet. They still must be created. class Customer { public string name; public decimal creditLimit; public uint customerID; } A class is a user-defined type, as opposed to a system-provided type. When you define a class, you actually create a new type in your application. To use a class that you have defined, you must first instantiate an object of that type by using the new keyword.
Syntax <class> <object> = new <class> Customer nextCustomer = new Customer();
Lecturer: Chhieng Sokha |Nguon Bunsour
47
Chapter 3: Creating Objects in C#
Introduction
You use namespaces to organize classes into a logically related hierarchy. Namespaces function as both an internal system for organizing your application and as an external way to avoid name clashes (collisions) between your code and other applications. Because more than one company may create classes with the same name, such as â&#x20AC;&#x153;Customer,â&#x20AC;? when you create code that may be seen or used by third parties, it is highly recommended that you organize your classes by using a hierarchy of namespaces. This practice enables you to avoid interoperability issues.
Definition
A namespace is an organizational system that is used to identify groups of related classes.
Creating a namespace To create a namespace, you simply type the keyword namespace followed by a name.
Lecturer: Chhieng Sokha |Nguon Bunsour
48
Chapter 3: Creating Objects in C#
Introduction
By using access modifiers, you can define the scope of class members in your applications. It is important to understand how access modifiers work because they affect your ability to use a class and its members.
Definition of scope
Scope refers to the region of code from which an element of the program can be referenced. For example, the weight member of the Lion class can be accessed only from within the Lion class. Therefore, the scope of the weight member is the Lion class. Items that are nested within other items are within the scope of those items. For example, Lion is within the ClassMain class, and therefore can be referenced from anywhere within ClassMain.
Example using System; namespace LearnCSharp.ClassExample { class ClassMain { public class Lion { public int age; private int weight; } static void Main(string[] args) { Lion zooLion = new Lion(); zooLion.age = 7; // the following line causes a compilation error zooLion.weight = 200; } } }
Lecturer: Chhieng Sokha |Nguon Bunsour
49
Chapter 3: Creating Objects in C#
Introduction
This lesson explains how to implement actions in C# by using methods.
Lesson objectives
After completing this lesson, you will be able to:
Lesson agenda
Write a method.
Pass parameters to a method.
Use the ref keyword to modify a parameter in a method.
Use the out keyword to initialize a value in a method.
Overload a method.
This lesson includes the following topics and activity:
How to Write a Method
How to Pass Parameters to a Method
How to Pass Parameters by Reference
How to Pass a Reference Type
How to Overload a Method
Practice: Writing and Calling a Method
Lecturer: Chhieng Sokha |Nguon Bunsour
50
Chapter 3: Creating Objects in C#
Introduction
A method is a class member that is used to define the actions that can be performed by that object or class.
Syntax
The syntax for declaring a method is as follows: [modifiers] return-type method-name ( [parameter-list] ) { statement-block }
Rules
Recommendation
The following rules apply to methods:
In the method declaration, you must always specify a return type. If the method is not designed to return a value to the caller, you specify a return type of void.
Even if the method takes no arguments, you must include a set of empty parentheses after the method name.
When calling a method, you must match the input parameters of the method exactly, including the return type, the number of parameters, their order, and their type. The method name and parameter list is known as the method signature.
The following are recommendations for naming methods:
The name of a method should represent the action that you want to carry out. For this reason, methods usually have action-oriented names, such as WriteLine and ChangeAddress. Methods should be named using Pascal case.
Lecturer: Chhieng Sokha |Nguon Bunsour
51
Chapter 3: Creating Objects in C#
Introduction
When a value type variable is passed to a method, the method receives a copy of the value that was assigned to the variable. The method uses this value to perform an action.
Example
For example, given the following class: class Lion { private int weight; public void SetWeight( int newWeight ) { weight = newWeight; } } If you pass the value of 200 to the SetWeight method: Lion bigLion = new Lion(); int bigLionWeight = 200; bigLion.SetWeight( bigLionWeight ); When the method is called, the value of bigLionWeight is copied to the newWeight parameter, and this changes the private member weight to 200.
Lecturer: Chhieng Sokha |Nguon Bunsour
52
Chapter 3: Creating Objects in C#
Introduction
Methods return only a single value, but sometimes you want a method to modify or return multiple values. You can achieve this by passing the method a reference to the variable that you want to modify. The method can use the reference to access the actual value and change the value. When a value is passed by reference, the method receives a reference to the actual valueâ&#x20AC;&#x201D;so any changes that the method makes to the variable are actually made to the object that was passed to the method.
The ref keyword
You declare that a parameter is a reference parameter by using the ref keyword. Use the ref keyword in the parameter list to indicate to the compiler that the value is being passed by reference. You also must use the ref keyword when you call the method.
The out keyword
By using the out keyword, you can eliminate the redundant initialization. Use the out keyword in situations where you want to inform the compiler that variable initialization is occurring within a method. When you use the out keyword with a variable that is being passed to a method, you can pass an uninitialized variable to that method.
Lecturer: Chhieng Sokha |Nguon Bunsour
53
Chapter 3: Creating Objects in C#
Introduction
When you pass a reference type variable to a method, the method can alter the actual value because it is operating on a reference to the same object.
Example 1
In the following example, a babyLion object is passed to an AddLion method, where the location member of babyLion is assigned the value Exhibit 3. Because the reference to the actual object is passed to the method, the method can change the value of location in the babyLion object. using System; namespace LearningCSharp { class MainClass { static void Main(string[] args) { Zoo myZoo = new Zoo(); Lion babyLion = new Lion(); myZoo.AddLion( babyLion ); // babyLion.location is Exhibit 3 } } class Lion { public string location; } class Zoo { public void AddLion( Lion newLion ) { newLion.location = "Exhibit 3"; } } }
Lecturer: Chhieng Sokha |Nguon Bunsour
54
Chapter 3: Creating Objects in C#
Introduction
When calling a method, you must match the input parameters exactly; including the return type, the number of parameters, and their order.
Definition
Method overloading is a language feature that enables you to create multiple methods in one class that have the same name but that take different signatures. By overloading a method, you provide the users of your class with a consistent name for an action while also providing them with several ways to apply that action.
Why overload?
Consider the following guidelines as you decide whether to use method overloading: ď&#x201A;§
Use overloading when you have similar methods that require different parameters.
ď&#x201A;§
Overloaded methods are a good way for you to add new functionality to existing code.
ď&#x201A;§
Use overloaded methods only to implement methods that provide similar functionality.
Lecturer: Chhieng Sokha |Nguon Bunsour
55
Chapter 3: Creating Objects in C#
Introduction
This lesson defines class constructors and explains how to use them to initialize objects.
Lesson objectives
After completing this lesson, you will be able to:
Lesson agenda
Write constructors.
Overload constructors.
This lesson includes the following topics and activity:
How to Initialize an Object
How to Overload a Constructor
Practice: Using Constructors
Lecturer: Chhieng Sokha |Nguon Bunsour
56
Chapter 3: Creating Objects in C#
Introduction
Every class implicitly or explicitly includes an instance constructor, which is a method that is automatically called by the runtime whenever an instance of the class is created.
Definition
Constructors are special methods that implement the actions that are required to initialize an object.
Creating a class constructor
The constructor method is defined by using the same name as the class in which it is declared.
Syntax
[modifiers] constructor-name ( [parameters] ) [initializer] statement-block For example, the following code contains a constructor: public class Lion { public Lion() { Console.WriteLine("Constructing Lion"); } } When the following code is executed, the Lion constructor is called when the object is instantiated: Lion babyLion = new Lion(); Console.WriteLine("Made a new Lion object");
readonly
The following output is produced: Constructing Lion Made a new Lion object When you use the readonly modifier on a member variable, you can only assign it a value when the class or object initializes, either by directly assigning the member variable a value, or by assigning it in the constructor. Use the readonly modifier when a const keyword is not appropriate because you are not using a literal valueâ&#x20AC;&#x201D;meaning that the actual value of the variable is not known at the time of compilation.
Lecturer: Chhieng Sokha |Nguon Bunsour
57
Chapter 3: Creating Objects in C#
Introduction
It is often useful to overload a constructor to allow instances to be created in more than one way.
Syntax
You overload a constructor in the same way that you overload a method: create a base class that contains two or more constructors with the same name but different input parameters.
Specifying an initialize Often when you have multiple constructors, you initialize each one in a similar manner. Rather than repeating the same code in each constructor, attempt to centralize common code in one constructor and call that from the other constructors. To call a specific constructor that is defined in the class itself, use the this keyword. When you add this to the constructor declaration, the constructor that matches the specified parameter list (has the same signature) is invoked. An empty parameter list invokes the default constructor.
Lecturer: Chhieng Sokha |Nguon Bunsour
58
Chapter 3: Creating Objects in C#
Introduction
This lesson introduces you to static class members. Static members belong to the class, rather than an instance. Static constructors are used to initialize a class.
Lesson objective(s)
After completing this lesson, you will be able to:
Lesson Agenda
Use static class members.
Initialize a class using a static constructor.
This lesson includes the following topics and activity:
How to Use Static Class Members
How to Initialize a Class
Practice: Using Static Class Members
Lecturer: Chhieng Sokha |Nguon Bunsour
59
Chapter 3: Creating Objects in C#
Introduction
Classes can have static members, such as properties, methods and variables. Static members are associated with the class, not with a specific instance of the class. Static members are useful when you want to initialize or provide a value that is shared by all instances of a class.
Static members
Because static members belong to the class, rather than an instance, they are accessed through the class, not through an instance of the class. The following complete code example shows how to use the static member family. using System; namespace StaticExample { class ZooDemo { static void Main(string[] args) { Console.WriteLine( "Family: {0}", Lion.family ); Console.ReadLine(); } } class Lion { public static string family = "felidae"; } } This code samples produces the following output: fedilae
Lecturer: Chhieng Sokha |Nguon Bunsour
60
Chapter 3: Creating Objects in C#
Introduction
Instance constructors are used to initialize an object. You can, however, write a constructor that initializes a class. This type of constructor is called a static constructor. You create a static constructor by using a static modifier.
Static constructor
A static constructor is sometimes referred to as a shared or global constructor because it does not operate on a specific instance of a class. You cannot call a static constructor directly. It is executed at most once before the first instance of the class is created or before any static methods are used. Therefore, a static constructor is useful for initializing values that will be used by all instances of the class.
Syntax
Like instance constructors, static constructors have the same name as the class, and an empty parameter list. You declare a static constructor by using the static modifier. It does not take an access modifier and it can coexist with an instance constructor. class Lion { static Lion() { // class-specific initialization } }
Lecturer: Chhieng Sokha |Nguon Bunsour
61
Chapter 3: Creating Objects in C#
Question
1. What is the default accessibility level of a class member? a. Public b. Private c. Internal A- ………………………………………………………………………………………………………. 2. What is the keyword that is used to inform the compiler that a variable is initialized within a method? A- ………………………………………………………………………………………………………. 3. What is the purpose of overloading a constructor? A- ………………………………………………………………………………………………………. 4. When and how often does a static constructor execute? A- ………………………………………………………………………………………………………. 5. Can you invoke a static method without instantiating an object? Why or why not? A- ……………………………………………………………………………………………………….
Lecturer: Chhieng Sokha |Nguon Bunsour
62
Norton University| DCS, Y2
Chapter 4: Implementing Object-Oriented Programming Techniques in C# Contents Lesson 1: Encapsulation (64) Lesson 2: Class Inheritance (72) Lesson 3: Polymorphism (75)
Chapter 4: Implementing OOP Techniques in C#
Lesson 1: Encapsulation Now that you've seen much of the syntax of C#, I'll show you how C# supports the another of the object-oriented principles - Encapsulation. This lesson will discuss Encapsulation with the following objectives: Understand the object-oriented principle of Encapsulation.
Learn the available modifiers for type members.
Protect object state through properties.
Control access to methods.
Learn how to modify types for assembly encapsulation
Introduction
Non-object-oriented programming languages consist of data, either in a database or in computer memory, and separate instructions for manipulating that data. These languages do not usually enforce any sort of relationship between the data and the code that manipulates the data. If any aspect of the data changes—for example, if a year field is changed from 2 digits to 4 digits then all of the code that uses that data must also be changed. Because the code is not closely related to the data, changing the code can be difficult and time-consuming.
Definition
In object-oriented programming, encapsulation is the enclosing of both properties and methods (the data and the code that manipulates that data) together in a common structure. Encapsulating both data and the actions that manipulate that data together in this way, and specifying the actions and properties of the object, creates a new data type called a class.
Benefit of encapsulation
When data and methods are encapsulated, you can specify methods and properties that define how the external user sees your information and how they can request actions from the object. By hiding information that users do not need, such as implementation information, the user can concentrate on only the useful characteristics of the object. For example, the internal mechanism of a telephone is hidden from the user. The wires, switches, and other internal parts of a telephone are encapsulated by its cover to allow the user to focus on using the phone and not on the internal operations of the telephone. This abstraction also enables you to easily change the implementation details of your application without the users of your object experiencing any change in the way they interact with the object. In object-oriented programming, you create objects that have state and behavior. An object's state is the data or information it contains. For example, if you have a BankAccount object, its state could be Amount and CustomerName. Behavior in an object is often represented by methods. For example, the BankAccount object's behavior could be Credit, Debit, and GetAmount. This sounds like a nice definition of an object, and it is, but you must also consider how this object will be used. When designing an object, you must think about how others could use it. In a bestcase scenario any program using the object would be well designed and the code would never change. However, the reality is that programs do change often and in a team environment many people touch the same code at one time or another. Therefore, it is beneficial to consider what could go wrong as well as the pristine image of how the object *should* be used. In the case of the BankAccount object, examine the situation where code outside of your object could access a decimal Amount field or a string CustomerName field. At
Lecturer: Chhieng Sokha |Nguon Bunsour
64
Chapter 4: Implementing OOP Techniques in C# the point of time that the code is written, everything would work well. However, later in the development cycle, you realize that the BankAccount object should keep track of an int CustomerID rather than string CustomerName because you don't want to duplicate relationships between information (or some other valid reason to alter the definition of internal state). Such changes cause a rippling effect in your code because it was built to use the BankAccount class, as originally designed (with CustomerName being a string), and you must now change code that accesses that state throughout your entire application. The object-oriented principle of Encapsulation helps avoid such problems, allowing you to hide internal state and abstract access to it though type members such as methods, properties, and indexers. Encapsulation helps you reduce coupling between objects and increases the maintainability of your code. Type Member Access Modifiers An access modifier allows you to specify the visibility of code outside a type or assembly. Access modifiers can be applied to either types or type members. A later section on Type Access Modifiers discusses modifiers that can be applied to types. This section discusses those modifiers that apply to type members and how they affect visibility. Generally, you should hide the internal state of your object from direct access from outside code. Then implement other members, such as methods and properties, that wrap that state. This allows the internal implementation of the state to change at will, while the members wrapping the state can still return a representation of the state that doesn't change. This means that outside code will access your object via members that wrap state and be guaranteed that the type of information extracted is consistent. Additionally, because external code doesn't have access to the internal state of your object, they can't alter that state in an inconsistent manner that could break the way your object works. The first step in encapsulating object state is to determine what type of access that outside code should have to the members of your type. This is performed with access modifiers. The type of access granted varies from no external access at all to full public access and a few variations in between the extremes. table 1-1 lists all of the type member access modifiers and explains their meaning. Table 1-1. Type member access modifiers control what code has access to a specified type member. Access Modifier private protected internal protected internal public
Description (who can access) Only members within the same type. (default for type members) Only derived types or members of the same type. Only code within the same assembly. Can also be code external to object as long as it is in the same assembly. (default for types) Either code from derived type or code in the same assembly. Combination of protected OR internal. Any code. No inheritance, external type, or external assembly restrictions.
Opening Type Members to public Access You've seen the public access modifier used in earlier parts of the C# Tutorial. Any time the public access modifier is used on a type member, calling code will be able to access the type member. If you make your type member public, you are giving Lecturer: Chhieng Sokha |Nguon Bunsour
65
Chapter 4: Implementing OOP Techniques in C# everyone permission to use it. Listing 1-1 shows an example of using the public access modifier on a method. Listing 1-1. Declaring a Method with a public Access Modifier: BankAccountPublic.cs using System; class BankAccountPublic { public decimal GetAmount() { return 1000.00m; } } The GetAmount() method in Listing 1-1 is public meaning that it can be called by code that is external to this class. Now, you can write the following code, elsewhere in your program, to use this method: BankAccountPublic bankAcctPub = new BankAccountPublic(); // call a public method decimal amount = bankAcctPub.GetAmount(); All you need to do, as shown above, is create an instance of the class that contains the method and then call the method through that instance. Because it is public, you won't have a problem. Remember that the default access for a type member is private, which we'll talk about next. This means that if you forget the public modifier, and didn't use any modifier at all, you would receive a compiler error. Hiding Type Members with private Access A private type member is one that can only be accessed by members within the same type. For example, if the BankAccount class has a private member, only other members of the BankAccount class can access or call that member. Although the default access for type members is private. Listing 1-2 shows how to use the private access modifier and offers an example of why you would want to use it. Listing 1-2. Declaring a private Field: BankAccountPrivate.cs using System; class BankAccountPrivate { private string m_name; public string CustomerName { get { return m_name; } set { m_name = value; } } } It's common to encapsulate the state of your type with properties. In Listing 4-2, you can see how the name of the customer is held in the m_name field, but it is wrapped (encapsulated) with the CustomerName property. Because m_name is declared as Lecturer: Chhieng Sokha |Nguon Bunsour
66
Chapter 4: Implementing OOP Techniques in C# private, code outside the BankAccountPrivate class can't access it directly. They must use the public CustomerName property instead. Now you can change the implementation of m_name in any way you want. For example, what if you wanted it to be an ID of type int and the CustomerName property would do a search to find the name or what if you wanted to have first and last name values that the CustomerName property could concatenate. There are all kinds of things happening to your code in maintenance that will causes implementation to change. The point is that private members allow the implementation to change without constraining the implementation or causing rippling effects throughout your code base that would have occurred if that external code had access to the members of your type. The private and public access modifiers are at the two extremes of access, either denying all external access or allowing all external access, respectively. The other access modifiers are like different shades of gray between these two extremes, including the protected modifier, discussed next. Access for Derived Types with the protected Access Modifier In some ways, the protected access modifier acts like both the private and public access modifiers. Like private, it only allows access to members within the same type, except that it acts like public only to derived types. Said another way, protected type members can only be accessed by either members within the same type or members of derived types. Returning to the BankAccount example, what if you needed to call code to close an account? Furthermore, what if there were different types of accounts? Each of these different account types would have their own logic for closing, but the basic process would be the same for all account types. If this sounds to you like the description of Polymorphism, you would be on the right track. In the case of closing an account, there are several things that need to be done like calculating interest that is due, applying penalties for early withdrawal, and doing the work to remove the account from the database. Individually, you don't want any code to call methods of the BankAccount class unless all of the methods are called and each method is called in the right order. For example, what if some code called the method to delete the account from the database and didn't calculate interest or apply penalties? Someone would lose money. Also, if the calling code were to delete the account first then the other methods wouldn't run into errors because the account information isn't available. Therefore, you need to control this situation and Listing 4-3 shows how you can do it. Listing 1-3. Declaring protected Methods: BankAccountProtected.cs using System; class BankAccountProtected { public void CloseAccount() { ApplyPenalties(); CalculateFinalInterest(); DeleteAccountFromDB(); }
Lecturer: Chhieng Sokha |Nguon Bunsour
67
Chapter 4: Implementing OOP Techniques in C#
protected virtual void ApplyPenalties() { // deduct from account } protected virtual void CalculateFinalInterest() { // add to account } protected virtual void DeleteAccountFromDB() { // send notification to data entry personnel } } The most important parts of Listing 1-3 are that the CloseAccount method is public and the other methods are protected. Any calling code can instantiate BankAccountProtected, but it can only call the CloseAccount method. This gives you protection from someone invoking the behavior of your object in inappropriate ways. Your business logic is sound. At the end of this section, you'll see an example of how to call the code in Listing 13. For now, it is essential that you see how the other pieces fit together first. If you only wanted the BankAccountProtected class to operate on its own members, you could have made the protected methods private instead. However, this code supports a framework where you can have different account types such as Savings, Checking, and more. You will be able to add new account types in the future because the BankAccountProtected class is designed to support them with protected virtual methods. Listings 1-4 and 1-5 show you the SavingsAccount and CheckingAccount classes that derive from the BankAccountProtected class. Listing 1-4. Derived SavingsAccount Class Using protected Members of its Base Class: SavingsAccount.cs using System; class SavingsAccount : BankAccountProtected { protected override void ApplyPenalties() { Console.WriteLine("Savings Account Applying Penalties"); } protected override void CalculateFinalInterest() { Console.WriteLine("Savings Account Calculating Final Interest"); }
}
protected override void DeleteAccountFromDB() { base.DeleteAccountFromDB(); Console.WriteLine("Savings Account Deleting Account from DB"); }
Notice how SavingsAccount derives from BankAccountProtected. SavingsAccount can access any of the protected members of the BankAccountProtected class which Lecturer: Chhieng Sokha |Nguon Bunsour
68
Chapter 4: Implementing OOP Techniques in C# is its base class. It demonstrates this fact via the call to base.DeleteAccountFromDB in it's DeleteAccountFromDB method. Each method of SavingsAccount has the protected access modifier also, which simply means that classes derived from SavingsAccount can access those SavingsAccount members with the protected access modifier. The same situation exists with the CheckingAccount class, shown in Listing 1-5. Listing 1-5. Derived CheckingAccount Class Using protected Members of its Base Class: CheckingAccount.cs using System; class CheckingAccount : BankAccountProtected { protected override void ApplyPenalties() { Console.WriteLine("Checking Account Applying Penalties");
} protected override void CalculateFinalInterest() { }
Console.WriteLine("Checking Account Calculating Final Interest");
protected override void DeleteAccountFromDB() { base.DeleteAccountFromDB(); Console.WriteLine("Checking Account Deleting Account from DB"); } } The CheckingAccount class in Listing 1-5 is implemented similar to SavingsAccount from Listing 1-6. If you were writing this, the difference would be that the methods of each class would have unique implementations. For example, the business rules associated with the final interest calculation would differ, depending on whether the account type was checking or savings. Notice the call to the base class method in the DeleteAccountFromlDB method in CheckingAccount. Just like SavingsAccount, CheckingAccount has access to BankAccountProtected's protected method because it is a derived class. This is a common pattern in polymorphism because derived classes often have a responsibility to call virtual base class methods to ensure critical functionality has the opportunity to execute. You would consult the method documentation to see if this was necessary. Without a protected access modifier, your only option would have been to make the base class method public; which, as explained earlier, is dangerous. To use the code from Listings 1-3, 1-4, and 1-5, you can implement the following code: BankAccountProtected[] bankAccts = new BankAccountProtected[2]; bankAccts[0] = new SavingsAccount(); bankAccts[1] = new CheckingAccount();
Lecturer: Chhieng Sokha |Nguon Bunsour
69
Chapter 4: Implementing OOP Techniques in C# foreach (BankAccountProtected acct in bankAccts) { // call public method, which invokes protected virtual methods acct.CloseAccount(); } Since both SavingsAccount and CheckingAccount derive from BankAccountProtected, you can assign them to the bankAccts array. They both override the protected virtual methods of BankAccountProtected, so it is the SavingsAccount and CheckingAccount methods that are called when CloseAccount in BankAccountProtected executes. Remember that the only reason the methods of SavingsAccount and CheckingAccount can call their virtual base class methods, as in the case of DeleteAccountFromDB, is because the virtual base class methods are marked with the protected access modifier. A Quick Word on internal and protected internal Access Modifiers In practice, most of the code you write will involve the public, private, and protected access modifiers. However, there are two more access modifiers that you can use in more sophisticated scenarios: internal and protected internal. You would use internal whenever you created a separate class library and you don't want any code outside of the library to access the code with internal access. The protected internal is a combination of the two access modifiers it is named after, which means either protected or internal. Access Modifiers for Types So far, the discussion of access modifiers has only applied to the members of types. However, the rules are different for the types themselves. When talking about types, I'm referring to all of the C# types, including classes, structs, interfaces, delegates, and enums. Nested types, such as a class defined within the scope of a class, are considered type members and fall under the same access rules as other type members. Types can have only two access modifiers: public or internal. The default, if you don't specify the access modifier, is internal. Looking at all of the classes used in this lesson, you can see that they are internal because they don't have an access modifier. You can explicitly specify internal like this: internal class InternalInterestCalculator { // members go here } Perhaps the InternalInterestCalculator, shown above, has special business rules that you don't want other code to use. Now, it is in a class library of its own and can only be accessed by other code inside of that same class library (DLL). Note: To be more specific, internal means that only code in the same assembly can access code marked as internal. However, discussing the definition of an assembly is outside the scope of this lesson, so I am simplifying the terminology.
Lecturer: Chhieng Sokha |Nguon Bunsour
70
Chapter 4: Implementing OOP Techniques in C# If you declared a class inside of a class library that you wanted other code to use, you would give it a public access modifier. The following code shows an example of applying the public access modifier to a type: public class BankAccountExternal { // members go here } Clearly, a bank account is something you would want to access from outside of a class library. Therefore, it only makes sense to give it a public access modifier as shown in the BankAccountExternal class above. Summary Encapsulation is an object-oriented principle of hiding the internal state and behavior of an object, making your code more maintainable. In C#, you can manage encapsulation with access modifiers. For example, the public access modifier allows access to any code but the private access modifier restricts access to only members of a type. Other access modifiers restrict access in the range somewhere between public and private. While you can use any of the access modifiers on type members, the only two access modifiers you can use on types are the public and internal.
Lecturer: Chhieng Sokha |Nguon Bunsour
71
Chapter 4: Implementing OOP Techniques in C#
Lesson 2: Class Inheritance This lesson teaches about C# Inheritance. Our objectives are as follows:
Implement Base Classes.
Implement Derived Classes.
Initialize Base Classes from Derived Classes.
Learn How to Call Base Class Members.
Learn How to Hide Base Class Members. Inheritance is one of the primary concepts of object-oriented programming. It allows you to reuse existing code. Through effective employment of reuse, you can save time in your programming.
Listing 2-1. Inheritance: BaseClass.cs using System; public class ParentClass { public ParentClass() { Console.WriteLine("Parent Constructor."); }
}
public void print() { Console.WriteLine("I'm a Parent Class."); }
public class ChildClass : ParentClass { public ChildClass() { Console.WriteLine("Child Constructor."); } public static void Main() { ChildClass child = new ChildClass();
}
}
child.print();
Output: Parent Constructor. Child Constructor. I'm a Parent Class.
Listing 2-1 shows two classes. The top class is named ParentClass and the main class is called ChildClass. What we want to do is create a child class, using existing code from ParentClass. First we must declare our intention to use ParentClass as the base class of ChildClass. This is accomplished through the ChildClass declaration public class Lecturer: Chhieng Sokha |Nguon Bunsour
72
Chapter 4: Implementing OOP Techniques in C# ChildClass : ParentClass. The base class is specified by adding a colon, ":", after the derived class identifier and then specifying the base class name. Note: C# supports single class inheritance only. Therefore, you can specify only one base class to inherit from. However, it does allow multiple interface inheritance, a subject covered in a later lesson. ChildClass has exactly the same capabilities as ParentClass. Because of this, you can also say ChildClass "is" a ParentClass. This is shown in the Main() method of ChildClass when the print() method is called. ChildClass does not have its own print() method, so it uses the ParentClass print() method. You can see the results in the 3rd line of output. Base classes are automatically instantiated before derived classes. Notice the output from Listing 2-1. The ParentClass constructor executed before the ChildClass constructor. Listing 2-2. Derived Class Communicating with Base Class: BaseTalk.cs using System; public class Parent { string parentString; public Parent() { Console.WriteLine("Parent Constructor."); } public Parent(string myString) { parentString = myString; Console.WriteLine(parentString); } public void print() { Console.WriteLine("I'm a Parent Class."); } } public class Child : Parent { public Child() : base("From Derived") { Console.WriteLine("Child Constructor."); } public new void print() { base.print(); Console.WriteLine("I'm a Child Class."); } public static void Main() { Child child = new Child(); child.print(); ((Parent)child).print(); } }
Lecturer: Chhieng Sokha |Nguon Bunsour
73
Chapter 4: Implementing OOP Techniques in C# Output: From Derived Child Constructor. I'm a Parent Class. I'm a Child Class. I'm a Parent Class.
Derived classes can communicate with base classes during instantiation. Listing 2-2 shows how this is done at the child constructor declaration. The colon, ":", and keyword base call the base class constructor with the matching parameter list. If the code had not appended base("From Derived") to the Derived constructor, the code would have automatically called Parent(). The first line of output shows the base class constructor being called with the string "From Derived". Sometimes you may want to create your own implementation of a method that exists in a base class. The Child class does this by declaring its own print() method. The Child print() method hides the Parent print() method. The effect is the Parent print() method will not be called, unless we do something special to make sure it is called. Inside the Child print() method, we explicitly call the Parent print() method. This is done by prefixing the method name with "base.". Using the base keyword, you can access any of a base class public or protected class members. The output from the Child print() method is on output lines 3 and 4. Another way to access base class members is through an explicit cast. This is done in the last statement of the Child class Main() method. Remember that a derived class is a specialization of its base class. This fact allows us to perform a cast on the derived class, making it an instance of its base class. The last line of output from Listing 2-2 shows the Parent print() method was indeed executed. Notice the new modifier on the Child class print() method. This enables this method to hide the Parent class print() method and explicitly states your intention that you don't want polymorphism to occur. Without the new modifier, the compiler will produce a warning to draw your attention to this. See the next lesson for a detailed discussion of polymorphism. In summary, you know how to create a derived/base class relationship. You can control instantiation of your base class and call its methods either implicitly or explicitly. You also understand that a derived class is a specialization of its base class.
Lecturer: Chhieng Sokha |Nguon Bunsour
74
Chapter 4: Implementing OOP Techniques in C# Lesson 3: Polymorphism This lesson teaches about Polymorphism in C#. Our objectives are as follows:
Learn What Polymorphism Is. Implement a Virtual Method. Override a Virtual Method. Use Polymorphism in a Program. Another primary concept of object-oriented programming is Polymorphism. It allows you to invoke derived class methods through a base class reference during run-time. This is handy when you need to assign a group of objects to an array and then invoke each of their methods. They won't necessarily have to be the same object type. However, if they're related by inheritance, you can add them to the array as the inherited type. Then if they all share the same method name, that method of each object can be invoked. This lesson will show you how to accomplish this.
Listing 3-1. A Base Class With a Virtual Method: DrawingObject.cs using System; public class DrawingObject { public virtual void Draw() { Console.WriteLine("I'm just a generic drawing object."); } }
Listing 3-1 shows the DrawingObject class. This will be the base class for other objects to inherit from. It has a single method named Draw(). The Draw() method has a virtual modifier. The virtual modifier indicates to derived classes that they can override this method. The Draw() method of the DrawingObject class performs a single action of printing the statement, "I'm just a generic drawing object.", to the console. Listing 3-2. Derived Classes With Override Methods: Line.cs, Circle.cs, and Square.cs using System; public class Line : DrawingObject { public override void Draw() { Console.WriteLine("I'm a Line."); } } public class Circle : DrawingObject { public override void Draw() { Console.WriteLine("I'm a Circle."); } } public class Square : DrawingObject { Lecturer: Chhieng Sokha |Nguon Bunsour
75
Chapter 4: Implementing OOP Techniques in C# public override void Draw() { Console.WriteLine("I'm a Square."); } } Listing 3-2 shows three classes. These classes inherit the DrawingObject class. Each class has a Draw() method and each Draw() method has an override modifier. The override modifier allows a method to override the virtual method of its base class at run-time. The override will happen only if the class is referenced through a base class reference. Overriding methods must have the same signature, name and parameters, as the virtual base class method it is overriding. Listing 3-3. Program Implementing Polymorphism: DrawDemo.cs using System; public class DrawDemo { public static int Main( ) { DrawingObject[] dObj = new DrawingObject[4]; dObj[0] dObj[1] dObj[2] dObj[3]
= = = =
new new new new
Line(); Circle(); Square(); DrawingObject();
foreach (DrawingObject drawObj in dObj) { drawObj.Draw(); } return 0; }
}
Listing 3-3 shows a program that uses the classes defined in Listing 3-1 and Listing 32. This program implements polymorphism. In the Main() method of the DrawDemo class, there is an array being created. The type of object in this array is the DrawingObject class. The array is named dObj and is being initialized to hold four objects of type DrawingObject. Next the dObj array is initialized. Because of their inheritance relationship with the DrawingObject class, the Line, Circle, and Square classes can be assigned to the dObj array. Without this capability, you would have to create an array for each type. Inheritance allows derived objects to act like their base class, which saves work. After the array is initialized, there is a foreach loop that looks at each element of the array. Within the foreach loop the Draw() method is invoked on each element of the dObj array. Because of polymorphism, the run-time type of each object is invoked. The type of the reference object from the dObj array is a DrawingObject. However, that doesn't matter because the derived classes override the virtual Draw() method of the DrawingObject class. This makes the overriden Draw() methods of the derived classes execute when the Draw() method is called using the DrawingObject base class reference from the dObj array. Here's what the output looks like:
Lecturer: Chhieng Sokha |Nguon Bunsour
76
Chapter 4: Implementing OOP Techniques in C# Output: I'm I'm I'm I'm
a Line. a Circle. a Square. just a generic drawing object.
The override Draw() method of each derived class executes as shown in the DrawDemo program. The last line is from the virtual Draw() method of the DrawingObject class. This is because the actual run-time type of the fourth array element was a DrawingObject object. The code in this lesson can be compiled with the following command line: csc DrawDemo.cs DrawingObject.cs Circle.cs Line.cs Square.cs
It will create the file DrawDemo.exe, which defaulted to the name of the first file on the command line. Summary You should now have a basic understanding of polymorphism. You know how to define a virtual method. You can implement a derived class method that overrides a virtual method. This relationship between virtual methods and the derived class methods that override them enables polymorphism. This lesson showed how to use this relationship between classes to implement polymorphism in a program.
Lecturer: Chhieng Sokha |Nguon Bunsour
77
Norton University| DCS, Y2
Chapter 5: Programming with C#
Contents Lesson 1: Arrays (79) Lesson 2: Collections (83) Lesson 3: Interfaces (93) Lesson 4: Exception Handling (99) Lesson 5: Delegates and Events (103)
Chapter 5: Programming with C#
Lesson 1: Array This tutorial is divided into the following sections:
Arrays in General Declaring Arrays Initializing Arrays Accessing Array Members Arrays are Objects Using foreach with Arrays
Arrays in General
C# arrays are zero indexed; that is, the array indexes start at zero. Arrays in C# work similarly to how arrays work in most other popular languages There are, however, a few differences that you should be aware of. When declaring an array, the square brackets ([]) must come after the type, not the identifier. Placing the brackets after the identifier is not legal syntax in C#. int[] table; // not int table[]; Another detail is that the size of the array is not part of its type as it is in the C language. This allows you to declare an array and assign any array of int objects to it, regardless of the array's length. int[] numbers; // declare numbers as an int array of any size numbers = new int[10]; // numbers is a 10-element array numbers = new int[20]; // now it's a 20-element array
Declaring Arrays
C# supports single-dimensional arrays, multidimensional arrays (rectangular arrays), and array-of-arrays (jagged arrays). The following examples show how to declare different kinds of arrays: Single-dimensional arrays: int[] numbers; Multidimensional arrays: string[,] names; Array-of-arrays (jagged): byte[][] scores; Declaring them (as shown above) does not actually create the arrays. In C#, arrays are objects (discussed later in this tutorial) and must be instantiated. The following examples show how to create arrays: Single-dimensional arrays: int[] numbers = new int[5]; Multidimensional arrays: string[,] names = new string[5,4];
Lecturer: Chhieng Sokha |Nguon Bunsour
79
Chapter 5: Programming with C# Array-of-arrays (jagged): byte[][] scores = new byte[5][]; for (int x = 0; x < scores.Length; x++) {
scores[x] = new byte[4];
} You can also have larger arrays. For example, you can have a three-dimensional rectangular array: int[,,] buttons = new int[4,5,3]; You can even mix rectangular and jagged arrays. For example, the following code declares a single-dimensional array of three-dimensional arrays of two-dimensional arrays of type int: int[][,,][,] numbers; Example
The following is a complete C# program that declares and instantiates arrays as discussed above. // arrays.cs using System; class DeclareArraysSample { public static void Main() { // Single-dimensional array int[] numbers = new int[5]; // Multidimensional array string[,] names = new string[5,4]; // Array-of-arrays (jagged array) byte[][] scores = new byte[5][]; // Create the jagged array for (int i = 0; i < scores.Length; i++) { scores[i] = new byte[i+3]; }
}
// Print length of each row for (int i = 0; i < scores.Length; i++) { Console.WriteLine("Length of row {0} is {1}", i, scores[i].Length); }
} Output Length of row 0 is 3 Length of row 1 is 4 Length of row 2 is 5 Length of row 3 is 6 Length of row 4 is 7 Lecturer: Chhieng Sokha |Nguon Bunsour
80
Chapter 5: Programming with C# Initializing Arrays
C# provides simple and straightforward ways to initialize arrays at declaration time by enclosing the initial values in curly braces ({}). The following examples show different ways to initialize different kinds of arrays. Note If you do not initialize an array at the time of declaration, the array members are automatically initialized to the default initial value for the array type. Also, if you declare the array as a field of a type, it will be set to the default value null when you instantiate the type.
Single-Dimensional Array int[] numbers = new int[5] {1, 2, 3, 4, 5}; string[] names = new string[3] {"Matt", "Joanne",
"Robert"};
You can omit the size of the array, like this: int[] numbers = new int[] {1, 2, 3, 4, 5}; string[] names = new string[] {"Matt", "Joanne", "Robert"}; You can also omit the new operator if an initializer is provided, like this: int[] numbers = {1, 2, 3, 4, 5}; string[] names = {"Matt", "Joanne", "Robert"}; Multidimensional Array int[,] numbers = new int[3, 2] {{1, 2}, {3, 4}, {5, 6}}; string[,] siblings = new string[2, 2] {{"Mike","Amy"}, {"Mary","Albert"}}; You can omit the size of the array, like this: int[,] numbers = new int[,] { {1, 2}, {3, 4}, {5, 6} }; string[,] siblings = new string[,] { {"Mike","Amy"}, {"Mary","Albert"} }; You can also omit the new operator if an initializer is provided, like this: int[,] numbers = { {1, 2}, {3, 4}, {5, 6} }; string[,] siblings = { {"Mike", "Amy"}, {"Mary", "Albert"} }; Jagged Array (Array-of-Arrays) You can initialize jagged arrays like this example: int[][] numbers = new int[2][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} }; You can also omit the size of the first array, like this: int[][] numbers = new int[][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} }; -orint[][] numbers = { new int[] {2,3,4}, new int[] {5,6,7,8,9} }; Notice that there is no initialization syntax for the elements of a jagged array. Lecturer: Chhieng Sokha |Nguon Bunsour
81
Chapter 5: Programming with C# Accessing Array Members
Accessing array members is straightforward and similar to how you access array members in C/C++. For example, the following code creates an array called numbers and then assigns a 5 to the fifth element of the array: int[] numbers = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; numbers[4] = 5; The following code declares a multidimensional array and assigns 5 to the member located at [1, 1]: int[,] numbers = { {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10} }; numbers[1, 1] = 5; The following is a declaration of a single-dimension jagged array that contains two elements. The first element is an array of two integers, and the second is an array of three integers: int[][] numbers = new int[][] { new int[] {1, 2}, new int[] {3, 4, 5} }; The following statements assign 58 to the first element of the first array and 667 to the second element of the second array: numbers[0][0] = 58; numbers[1][1] = 667;
Arrays are Objects In C#, arrays are actually objects. System.Array is the abstract base type of all array types. You can use the properties, and other class members, that System.Array has. An example of this would be using the Length property to get the length of an array. The following code assigns the length of the numbers array, which is 5, to a variable called LengthOfNumbers: int[] numbers = {1, 2, 3, 4, 5}; int LengthOfNumbers = numbers.Length; The System.Array class provides many other useful methods/properties, such as methods for sorting, searching, and copying arrays. Using foreach Arrays
C# also provides the foreach statement. This statement provides a simple, clean way to on iterate through the elements of an array. For example, the following code creates an array callednumbers and iterates through it with the foreach statement: int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0}; foreach (int i in numbers) { System.Console.WriteLine(i); } With multidimensional arrays, you can use the same method to iterate through the elements, for example: int[,] numbers = new int[3, 2] {{9, 99}, {3, 33}, {5, 55}}; foreach(int i in numbers) { Console.Write("{0} ", i); } The output of this example is: 9 99 3 33 5 55
Lecturer: Chhieng Sokha |Nguon Bunsour
82
Chapter 5: Programming with C#
Lesson 2: Using Collections This tutorial is divided into the following sections:
What Are Lists, Queues, Stacks, and Hash Tables?
How to Use the ArrayList Class
How to Use Stacks and Queues
How to Use Hash Tables
Collections Classes The namespaces System.Collections and System.Collections.Genericintroduced a large number of commonly used collections you can choosefrom according to your application. Selecting the right collection is very important to avoid problems that may arise when your application is nearing completion.
Array List Collection
In the following sections, some of the most commonly used collections of the System.Collections are introduced: ArrayList Stack Queue Hashtable And Others… An ArrayList collection is a dynamic array. You can add items to and remove items from the collection at run time. The elements of an ArrayList collection are not sorted automatically, but you can use the ArrayList.Sort method to do that. The capacity of an ArrayList collection is the number of elements that can be stored in the collection. The default capacity is 16. When you add more elements to the collection, the capacity is automatically increased. You can set the capacity by using the appropriate method shown in Table 2.1. To create a simple and quick ArrayList collection program, use the following procedure: 1. Add the following directive to your program: using System.Collections; 2.
Declare an empty ArrayList collection with the statement: ArrayList <ArrayList-name> = new ArrayList();
3.
Add elements to the collection by using the method Add.
Display the elements by using a foreach loop, which is designed to work with collections. Table 2.1 lists other ArrayList methods and properties that you can use in your applications. ArrayList Members The following table contains the commonly used members of the ArrayList collection. 4.
Lecturer: Chhieng Sokha |Nguon Bunsour
83
Chapter 5: Programming with C# Table 2-1: Commonly used members of the ArrayList class Property/Method Description
Public constructors
Add Capacity Clear Contains Count
Creates and initializes an empty ArrayList with the default capacity. Creates and initializes an ArrayList with the elements of a specified collection. Creates and initializes an ArrayList with an initial specified capacity. Adds an item to the end of the collection. Retrieves or sets the number of items in the collection. Removes all items from the Collection. Checks if a specific item is in the collection. Retrieves the number of items in the ArrayList collection. Retrieves the index of the first matching item. Retrieves the index of the first matching item in the portion of the collection starting at the
IndexOf
specified startingIndex. Retrieves the index of the first matching item in the portion of the collection starting at the specified startingIndex and conains the specified number of items.
Remove
Inserts an item into the ArrayList collection at the specified index. Retrieves or sets the value of an item that corresponds to a specified index (e.g., myList["003"]) Removes the first item that matches the specified item.
RemoveAt
Removes the item at the specified index.
Insert
Item
RemoveRange
Reverse
Lecturer: Chhieng Sokha |Nguon Bunsour
Syntax
ArrayList() ArrayList(ICollection collection) ArrayList(int capacity) public virtual int Add(object item) public virtual int Capacity {get; set;} public virtual void Clear() public virtual bool Contains(object item) public virtual int Count {get;}
public virtual int IndexOf(object item) public virtual int IndexOf(object item, int startingIndex) public virtual int IndexOf(object item, int startingIndex, int number)
public virtual void Insert(int index, object item) public virtual object this [int index] {get; set;} public virtual void Remove(object item) public virtual void RemoveAt(int index)
Removes a range of items specified by count and starting at the specified index. Reverses the order of the items in the ArrayList collection.
public virtual void RemoveRange(int index, int count)
Reverses the order of the items in a range specified by count and starting at index.
public virtual void Reverse(int index, int count)
public virtual void Reverse()
84
Chapter 5: Programming with C# Sorts the items in the collection.
Sort
Sorts the items in the collection by using a comparer. Sorts the items in the collection by using a comparer, index, and count.
ToArray TrimToSize
Example 2.1
Copies all the items in the collection to an object array. Sets the capacity of the collection to the existing number of items.
public virtual void Sort() public virtual void Sort(IComparer comparer) public virtual void Sort(int index, int count, IComparer comparer) public virtual object[] ToArray() public virtual void TrimToSize()
In the following example, you initialize an empty ArrayList collection and display its capacity. You then add five items to the collection and display the number of items and the new capacity. You also sort the collection and display the items before and after the sorting. // ArrayList.cs using System; using System.Collections; public class MyClass { public static void Main() { // Create an ArrayList: ArrayList myArrayList = new ArrayList(); // Display the initial capacity: Console.WriteLine("The initial capacity is: {0}", myArrayList.Capacity); // Initialize the list with some elements: myArrayList.Add("SNL"); myArrayList.Add("Mad TV"); myArrayList.Add("Seinfeld"); myArrayList.Add("Everybody Loves Raymond"); myArrayList.Add("Married with Children"); // Display the number of items: Console.WriteLine("The number of items: {0}", myArrayList.Count); // Display the new capacity: Console.WriteLine("The capacity is now: {0}", myArrayList.Capacity); // Display the elements in the list: Console.WriteLine("\nThe contents of the ArrayList: "); DisplayIt(myArrayList); // Sort and display the list: myArrayList.Sort(); Console.WriteLine("\nThe contents of the sorted ArrayList: "); DisplayIt(myArrayList); } public static void DisplayIt(ArrayList myList) { foreach (object item in myList) Console.WriteLine("{0}", item); } }
Lecturer: Chhieng Sokha |Nguon Bunsour
85
Chapter 5: Programming with C# Output: The initial capacity is: 0 The number of items: 5 The capacity is now: 8 The contents of the ArrayList: SNL Mad TV Seinfeld Everybody Loves Raymond Married with Children The contents of the sorted ArrayList: Everybody Loves Raymond Mad TV Married with Children Seinfeld SNL The Stack Collection
The Stack collection is distinguished as being â&#x20AC;&#x153;last-in, first-outâ&#x20AC;? (LIFO collection classes). When you insert some elements in the stack, the last element pushed in is the first one that pops out. The capacity of a Stack collection is the number of elements that can be stored in the collection. The default initial capacity is 10. When you add more elements to the collection, the capacity is automatically increased. To try a simple and quick Stack program, use the following procedure: 1. Add the following directive to your application: using System.Collections; 2. Declare the Stack collection with one of the constructors listed in Table 2-2, such as: Stack <stack-name> = new Stack(); 3. Add elements to the collection by using the method Push. 4. Use the method Pop to remove and display the elements of the stack. 5. Use the method Peek to display the element at the top of the stack. 6. Display the elements by using a foreach loop, which is designed to work with collections.
Stack Members
The following are the commonly used members of the Stack collection. Table 2-2: Commonly used members of the Stack class
Property/Method
Description
Syntax
Public constructors
Creates and initializes an empty Stack collection with the default capacity.
Stack()
Stack(ICollection Creates and initializes a Stack collection) collection with the elements of a specified collection.
Clear
Creates and initializes a Stack collection with an initial specified capacity or the default capacity, whichever is greater.
Stack(int capacity)
Removes all items from the collection.
public virtual void Clear()
Lecturer: Chhieng Sokha |Nguon Bunsour
86
Chapter 5: Programming with C# Contains
Checks if a specific item is in the public virtual bool Contains(object item) collection. public virtual int Count Count Retrieves the number of items {get;} in the collection. public virtual object Peek() Peek Returns the item at the top of the collection without removing it. public virtual object Pop() Pop Removes and returns the item at the top of the collection. public virtual void Push Inserts an item in the Stack Push(object item) collection. public virtual object[] ToArray Copies all the items in the ToArray() collection to an object array. ** For a list of all the members of the collection, see the Stack help file. Example 2.2
In the following example, a Stack collection is initialized with four string objects and then displayed using foreach. As you can see, the first inserted item is the last one displayed. // Stack1.cs using System; using System.Collections; public class MyClass { public static void Main() { // Create a stack object: Stack myStack = new Stack(); // Insert elements: myStack.Push("out"); myStack.Push("first"); myStack.Push("in"); myStack.Push("Last"); // Display the elements: foreach(object item in myStack) { Console.Write("{0} ", item); } } } Output: Last in first out
Lecturer: Chhieng Sokha |Nguon Bunsour
87
Chapter 5: Programming with C# Example 2.3
In the following example, a Stack collection is initialized with an array.The items in the collection are removed one by one until it is empty. The number of the remaining items and the item on the top of the collection are displayed after each removal. // Stack2.cs using System; using System.Collections; public class MyClass { public static void Main() { // Declare an array collection: string[] myArr = {"Tom", "Dick", "Harry"}; // Use the array to initialize a stack object: Stack myStack = new Stack(myArr); // Display the number of elements: Console.WriteLine("The number of elements is: {0} ", myStack.Count); // Display all: Console.Write("Elements: "); foreach (object obj in myStack) Console.Write(obj+""); Console.WriteLine(); // Display and remove items one by one: for (int i = myStack.Count;i>0; i--) { Console.WriteLine("\nTop element on the stack is now: {0}", myStack.Peek()); Console.WriteLine("The number of elements is now: {0}", myStack.Count); Console.WriteLine("Element '{0}' has been removed from the stack.", myStack.Pop()); } // Display the number of elements: Console.WriteLine("\nThe number of elements is now: {0} ", myStack.Count); } } Output: The number of elements is: 3 Elements: Harry Dick Tom Top element on the stack is now: Harry The number of elements is now: 3 Element 'Harry' has been removed from the stack. Top element on the stack is now: Dick The number of elements is now: 2 Element 'Dick' has been removed from the stack. Top element on the stack is now: Tom The number of elements is now: 1 Element 'Tom' has been removed from the stack. The number of elements is now: 0
Lecturer: Chhieng Sokha |Nguon Bunsour
88
Chapter 5: Programming with C# The Queue Collection
The Queue collection represents a â&#x20AC;&#x153;first-in, first-outâ&#x20AC;? (FIFO) collection of objects. When you insert some elements in the queue, the first element inserted is the first one to be extracted. The capacity of a Queue collection is the number of elements that can be stored in the collection. The default initial capacity is 32. When you add elements to the collection, the capacity is automatically increased. The growth factor is the number by which the current capacity is multiplied when the capacity increases. Unless it is set by the appropriate constructor, the growth factor takes the default value 2.0. To create a simple and quick Queue collection program, use the following procedure: 1. Add the following directive to your program: using System.Collections; 2. Declare an empty Queue collection with the statement: Queue <queue-name> = new Queue(); 3. Add elements to the collection by using the method Enqueue. 4. Use the method Dequeue to remove and display the elements of the queue. 5. Use the method Peek to display the element at the beginning of the queue. 6. Display the elements by using a foreach loop, which is designed to work with collections.
Queue Members
The following table lists other Queue methods and properties that you can use in your applications. Table 2-3: lists the commonly used members of the Queue collection.
Property/Method Public constructors
Description
Syntax
Creates and initializes an empty Queue collection with the default capacity (32) and default growth factor (2.0). Creates and initializes a Queue collection with the elements of a specified collection.
Queue()
Creates and initializes a Queue collection with an initial specified capacity or the default capacity.
Queue(int capacity)
Creates and initializes a Queue collection with an initial specified capacity and a specified growth factor.
Queue(int capacity, float growth)
Clear
Removes all items from the collection.
Contains
Checks if a specific item is in the collection
Count
Retrieves the number of items in the collection Removes and returns the item at the beginning of the collection. Inserts an item at the end of the collection.
Public virtual void Clear() public virtual bool Contains(object item) public virtual int Count {get;} Public virtual object Dequeue() public virtual void Enqueue(object item) public virtual object Peek() public virtual object[] ToArray() public virtual void TrimToSize()
Dequeue Enqueue Peek ToArray TrimToSize
Returns the item at the beginning of the collection. Copies all the items in the collection to an object array. Sets the capacity of the collection to the existing number of items.
Queue(ICollection collection)
For a list of all the members of the collection, see the Queue help file.
Lecturer: Chhieng Sokha |Nguon Bunsour
89
Chapter 5: Programming with C# Example 2.4
In the following example, a Queue collection is initialized with four elements and then displayed by using the foreach statement. // Queue1.cs using System; using System.Collections; public class MyClass { public static void Main() { // Create an empty Queue collection: Queue myQueue = new Queue(); // Add items to the collection: myQueue.Enqueue("First"); myQueue.Enqueue("in"); myQueue.Enqueue("first"); myQueue.Enqueue("out"); // Display the contents: foreach(string item in myQueue) { Console.Write("{0} ", item); } } }
Output: First in first out
Example 2.5
In the following example, a Queue collection is initialized from an array collection. The collection items are removed and displayed by using the Dequeue method until the collection is empty. The number of items is displayed before and after the removal. // Queue2.cs using System; using System.Collections; public class MyClass { public static void Main() { // Declare an array collection: string[] myArr = {"Tom", "Dick", "Harry"}; // Use the array to initialize a Queue object: Queue myQueue = new Queue(myArr); // Display the number of items: Console.WriteLine("The number of items is: {0}", myQueue.Count); // Display and remove items: while(myQueue.Count != 0) { Console.Write(myQueue.Dequeue()+""); } Console.WriteLine("\nThe number of items is now: {0}", myQueue.Count); } }
Lecturer: Chhieng Sokha |Nguon Bunsour
90
Chapter 5: Programming with C# Output: The number of items is: 3 Tom Dick Harry The number of items is now: 0 The Hashtable Collection
The Hashtable collection is a collection of key/value entries. The entries are sorted according to the hash code of the key. Items in a Hashtable are of the type DictionaryEntry, where each entry has a key and a value. The capacity of a Hashtable is the number of items that can be stored in the Hashtable. The default initial capacity for a Hashtable is zero. When you add items to it, the capacity is automatically increased. To create a simple and quick Hashtable program, use the following procedure: 1. Add the following directive to your program: using System.Collections; 2. Declare an empty Hashtable collection with the statement: Hashtable <Hashtable-name> = new Hashtable(); 3. Add elements to the collection by using the method Add. 4. Display the elements by using a foreach loop, which is designed to work with collections. When you display items of a Hashtable, you can use the DictionaryEntry object like this example
Hashtable Members
foreach (DictionaryEntry de in myHashtable) Console.WriteLine("{0} {1}", de.Key, de.Value); You can also use the Keys property to display values that correspond to each key. For example: foreach (string k in myHashtable.Keys) Console.WriteLine("{0} {1}", k, myHashtable[k]); The following table contains the commonly used members of the Hashtable class. Table 11-5: Commonly used members of the Hashtable class
Property/Method
Public constructors
Add
Description
Syntax
Creates and initializes an empty Hashtable collection with the default capacity and load factor. Creates and initializes a Hashtable collection with an initial specified capacity and the default load factor. Creates and initializes a Hashtable collection with an initial specified capacity and specified loadFactor. Adds an item with a specified key and value to the collection.
Hashtable()
Clear
Removes all items from the collection
Contains
Checks if a specified key is in the collection. Same as Contains.
ContainsKey ContainsValue Count Item
Checks if a specified value is in the collection. Retrieves the number of items in the collection. Retrieves or sets the value of an item that corresponds to a specified key
Lecturer: Chhieng Sokha |Nguon Bunsour
Hashtable(int Capacity)
Hashtable(int capacity, float loadFactor) public virtual void Add(object key, object value) public virtual void Clear() public virtual bool Contains(object key) public virtual bool ContainsKey(object key) public virtual bool Contains(object value) public virtual int Count {get;} public virtual object this [object key]
91
Chapter 5: Programming with C# (e.g., myList["003"]). Retrieves an ICollection containing the keys in the collection.
Keys Remove Values
Removes an item with a specified key from the collection. Retrieves an ICollection containing the values in the collection.
{get; set;} public virtual ICollection Keys {get;} public virtual void Remove(object key) public virtual ICollection Values{get;}
For a list of all the members of the collection, see the Hashtable help file. Example 2.6
In the following example, a Hashtable collection is initialized with the area codes for some of the states in the U.S. The area codes and the states are displayed. using System; using System.Collections; namespace Hashtable1 { class Program { static void Main(string[] args) { // Creates a Hashtable object: Hashtable AreaCodeHash = new Hashtable(); // Initializes the Hashtable. AreaCodeHash.Add("201", "New Jersey"); AreaCodeHash.Add("337", "Louisiana"); AreaCodeHash.Add("425", "Washington"); AreaCodeHash.Add("415", "California"); AreaCodeHash.Add("503", "Oregon"); AreaCodeHash.Add("489", "Texas"); // Displays the contents of the Hashtable. DisplayIt(AreaCodeHash); // Display the number of elements: Console.WriteLine("Number of elements: {0}", AreaCodeHash.Count); } public static void DisplayIt(Hashtable AreaCodeHash) { Console.WriteLine("Area Code\tState"); foreach (string k in AreaCodeHash.Keys) Console.WriteLine("{0, -16}{1}", k, AreaCodeHash[k]); } } }
Output: Area Code State 337 Louisiana 489 Texas 425 Washington 503 Oregon 415 California 201 New Jersey Number of elements: 6
Lecturer: Chhieng Sokha |Nguon Bunsour
92
Chapter 5: Programming with C#
Lesson 3: Interfaces This tutorial is divided into the following sections:
What Is an Interface?
How to Use an Interface
How to Work with Objects That Implement Interfaces
How to Inherit Multiple Interfaces
Interfaces and the .NET Framework
Introduction
An interface is in some ways like an abstract class. It defines a set of methods, properties, indexers, and events, just like any other class. However, it provides no implementation. The class that inherits the interface must provide the implementation.
Definition
Interface is a reference type that defines a contract in that a class that implements an interface must implement every aspect of that interface exactly as it is defined. Like classes, interfaces can contain methods, properties, indexers, and events as members. Other types implement an interface to guarantee that they support certain operations. The interface specifies the members that must be supplied by classes or other interfaces that implement it. Providing an implementation of the methods, properties, indexers, and events that are declared by the interface is called implementing the interface. Although C# imposes a single inheritance rule for classes, the language is designed so that a class can inherit multiple interfaces.
Purpose
Declaring an interface
There are several reasons that you may want to use interfaces instead of class inheritance:
Interfaces are better suited to situations in which your applications require many possibly unrelated object types to provide certain functionality.
Interfaces permit polymorphism between classes with different base classes.
Interfaces are more flexible than base classes because you can define a single implementation that can implement multiple interfaces.
Interfaces are better in situations in which you do not need to inherit implementation from a base class.
Interfaces are useful in cases where you cannot use class inheritance.
You use the interface keyword to declare an interface. The syntax is: [attributes] [access-modifier] interface interface-name [:base-list] { interface-body }
Interface Implementation
The interface can be implemented by a class or a struct as shown in this example: class MyClass: IMyInterface1 { // class implementation } By this declaration the class MyClass is obligated to implement all members of the interface IMyInterface.
Lecturer: Chhieng Sokha |Nguon Bunsour
93
Chapter 5: Programming with C# It is also possible for a class to implement more than one interface: class MyClass: IMyInterface1, IMyInterface2 { // class implementation } A class can also implement another class in addition to the interfaces: class MyClass: MyBaseClass, IMyInterface1, IMyInterface2 { // class implementation } In the following example, the class Point implements the interface IPoint. Notice that all the fields are included in the class but none are included in the interface. Example 3.1
// Interface.cs using System; interface IPoint { // Property signatures: int Myx { get; set; } int Myy { get; set; } } class Point : IPoint { // Fields: private int x; private int y; // Constructor: public Point(int x, int y) { this.x = x; this.y = y; } // Property implementation: public int Myx { get { return x; } set { x = value; } } public int Myy { get { return y; } set { y = value; } } public static void DisplayMyPoint(IPoint myPoint) { Console.WriteLine("({0},{1})", myPoint.Myx, myPoint.Myy); } } class MyClass { static void Main() { Point myPoint = new Point(12, 300); Console.Write("My point is created at: "); Point.DisplayMyPoint(myPoint); } }
Lecturer: Chhieng Sokha |Nguon Bunsour
94
Chapter 5: Programming with C# Out put My point is created at: (12,300) Notes about the preceding example: 1. If you donâ&#x20AC;&#x2122;t implement all the members of the interface, you get a compilation error. Try commenting the properties (Myx and Myy) in the class to see the compiler error message. 2. Notice that the class can contain members other than the members of the interface, such as the method DisplayMyPoint. 3. Notice also that it is possible to pass a parameter of the type IPoint to the method DisplayMyPoint. You can, of course, pass a parameter of the type Point instead. Explicit Interface Implementation
Consider a class, MyClass, that implements an interface, IMyInterface. It is possible to implement the interface member, MyMethod, like this: string IMyInterface.MyMethod() { // interface implementation } In this example, MyMethod is qualified by the interface name, IMyInterface: IMyInterface.MyMethod() This is called explicit interface implementation. Assume that you created an object from MyClass using the following statement: MyClass mc = new MyClass(); You can also create an interface object by casting the class object: IMyInterface mi = (IMyInterface) mc; In this case, you can only access MyMethod through the interface object mi. For example: Console.Write(mi.MyMethod()); Attempting to access MyMethod through the class member mc would generate a compilation error: Console.Write(mc.MyMethod()); // error So, when do you need to use this code? There are cases in which the use of explicit interface implementation becomes necessary, such as when the class is implementing two interfaces and both interfaces contain a method named MyMethod. If the first interface object is mi1 and the second interface object is mi2, accessing MyMethod through interface objects does not cause any ambiguity. That is: Console.Write(mi1.MyMethod()); Console.Write(mi2.MyMethod()); In fact, using the class object to access the method will cause ambiguity. The following example demonstrates a temperature converter that converts from Fahrenheit to Celsius and vice versa. The program contains two interfaces: ITemp1 and ITemp2. Each contains a method named Convert. The class TempConverter explicitly implements the two interfaces. In the Main method, two interface objects, iFC and iCF, are used to access the Convert method.
Lecturer: Chhieng Sokha |Nguon Bunsour
95
Chapter 5: Programming with C# Example 3.2 //Interface Implementation.cs using System; public interface ITemp1 { double Convert(double d); } public interface ITemp2 { double Convert(double d); } public class TempConverter : ITemp1, ITemp2 { double ITemp1.Convert(double d) { // Convert to Fahrenheit: return (d * 1.8) + 32; } double ITemp2.Convert(double d) { // Convert to Celsius: return (d - 32) / 1.8; } } class MyClass { public static void Main() { // Create a class instance: TempConverter cObj = new TempConverter(); // Create instances of interfaces // Create a From-Celsius-to-Fahrenheit object: ITemp1 iCF = (ITemp1)cObj; // Create From-Fahrenheit-to-Celsius object: ITemp2 iFC = (ITemp2)cObj; // Initialize variables: double F = 32; double C = 20; // Print results: Console.WriteLine("Temperature {0} C in Fahrenheit: {1:F2}", C, iCF.Convert(C)); Console.WriteLine("Temperature {0} F in Celsius: {1:F2}", F, iFC.Convert(F)); } }
Output:
Temperature 20 C in Fahrenheit: 68.00 Temperature 32 F in Celsius: 0.00 Using is to Test Types The operator is is used to test the type of various objects at run time. It is used in the following form: expression is type where: type is a reference type. expression is the object to be tested. The result of this operation is either true or false. For example, the following expression: myObj is MyClass is used to check if the object myObj is an instance of the class MyClass. The result of the expression renders true if it is an instance of MyClass; false otherwise. Lecturer: Chhieng Sokha |Nguon Bunsour
96
Chapter 5: Programming with C# Also, the expression: myObj is IMyInterface is used to check if the object myObj is an instance of a class that implements the interface IMyInterface. The result is either true or false. In the following example, the operator is is used to check if the type of an object is an instance of MyClass and the two interfaces I1 and I2. Example 3.3
//The is operator.cs using System; interface I1 { } interface I2 { } class Class1 : I1, I2 { } class MyClass { static bool TestType(object obj) { if (obj is I1 & obj is I2 & obj is Class1) return true; else return false; } public static void Main() { Class1 c = new Class1(); Console.WriteLine("The result of the test: {0}", TestType(c)); } }
Output:
The result of the test: True Using as to Test Types The operator as is used to convert an expression to a specified reference type. It is used according to the form: expression as type where: type is a reference type. expression is the object to be converted. If the conversion is successful, it returns the value of the expression; null otherwise. This expression is equivalent to casting expression with type except that it doesnâ&#x20AC;&#x2122;t throw an exception if the conversion fails. The expression is equivalent to the following conditional expression: expression is type ?(type) expression :(type) null; In the following example, the method TestType is used to test objects of various types. Notice that only reference-type objects are converted.
Lecturer: Chhieng Sokha |Nguon Bunsour
97
Chapter 5: Programming with C# Example 3.4
// The as operator using System; public class MyClass_as { static void TestType(object o) { if (o as MyClass != null) Console.WriteLine ("The object \"{0}\" is a class.", o); else if (o as string != null) Console.WriteLine ("The object \"{0}\" is a string.", o); else Console.WriteLine ("The object \"{0}\" is not a reference type.", o); Console.ReadLine(); } static void Main() { MyClass mc = new MyClass(); string myString = "Hello, World!"; int myInt = 123; TestType(mc); TestType(myString); TestType(myInt); } }
Output: The object "MyClass" is a class. The object "Hello, World!" is a string. The object "123" is not a reference type.
Lecturer: Chhieng Sokha |Nguon Bunsour
98
Chapter 5: Programming with C#
Lesson 4: Exception Handling After completing this lesson, you will be able to:
Explain exception handling.
Use the throw keyword.
Use the try, catch, and finally keywords.
Catch specific exception types.
Introduction
An exception is any error condition or unexpected behavior that is encountered by an executing program. Exceptions can be raised because of a fault in your code or in code that you call, resources not being available, such as running out of memory or not being able to locate a particular file, or other unexpected conditions.
Using try/catch to Catch exception
The following examples represent situations that might cause exceptions: Scenario Solution Opening a file Before opening a file, check that the file exists and that you can open it. Reading an XML document You will normally read well-formed XML documents, but you should deal with the exceptional case where the document is not valid XML. This is a good example of where to rely on exception handling. Accessing an invalid member of an array
If you are the user of the array, this is an application bug that you should eliminate. Therefore, you should not use exception handling to catch this exception.
Dividing a number by zero
This can normally be checked and avoided.
Converting between types using the System.Convert classes
With some checking, these can be avoided.
You can handle these error conditions by using try, catch, and finally keywords. Trying Code and Catching Exceptions
C# makes it easy to separate the code that implements the main flow of the program from the error handling code, by using exceptions and exception handlers. To write exception-aware programs, you need to do two things: 1. Write your code inside a try block (try is a keyword). When the code runs, it attempts to execute all the statements inside the try block, and if none of the statements generates an exception, they all run, one after the other, to completion. However, if an error condition occurs, execution jumps out of the try block and into a catch handler. 2. Write one or more catch handlers (catch is a keyword) immediately after the try block to handle any possible error conditions. If any one of the statements inside the try block causes an error, the runtime generates and throws an exception. The runtime then examines the catch handlers after the try block and transfers control directly to a matching handler. Catch handlers are designed to trap particular exceptions, allowing you to provide different handlers for the different errors that can happen.
Lecturer: Chhieng Sokha |Nguon Bunsour
99
Chapter 5: Programming with C# Example 4.1
The following code shows a Text Box named numberOfTickets into which the user types the number of tickets that they want to purchase. Text boxes provide access to their contents through the Text property, which is a string type, so the user input must be converted to an integer. The following code uses a byte to hold the number of tickets: numberOfTickets = new TextBox(); ... byte tickets = Convert.ToByte(numberOfTickets.Text);
The Convert.ToByte method throws an exception, System.FormatException if the user enters a character string. The following code demonstrates how to handle this situation: try { byte tickets = Convert.ToByte(numberOfTickets.Text); } catch { MessageBox.Show("Please enter a number"); }
Handling specific Exceptions
The try block encloses the code that may throw an exception. The catch block catches all exceptions that are thrown in the try block, because catch does not specify the exception that it will handle. You can also specify the type of the exception that you want to catch, as shown in the following code: try { byte tickets = Convert.ToByte(numberOfTickets.Text); } catch (FormatException) { MessageBox.Show("Format Exception: please enter a number"); }
Using the finally Keyword
When the user enters text instead of numbers, a message box appears containing an appropriate message. When an exception occurs, execution stops and control is given to the closest exception handler. This often means that lines of code that you expect to always be called are not executed. However, some resource cleanup, such as closing a file, must always be executed even if an exception is thrown. To accomplish this, you can use a finally block. A finally block is always executed, regardless of whether an exception is thrown. FileStream xmlFile = null; try { xmlFile = new FileStream("XmlFile.xml", FileMode.Open); } catch( System.IO.IOException e ) { return; } finally { if ( xmlFile != null ) { xmlFile.Close(); } }
In this example, the finally block is used to close the file, if it was open. Throw keyword
Sometimes you may want to catch an exception, do some work to handle the exception, and then pass an exception on to the calling code. This is called throwing an exception. It is good coding practice to add information to an exception that is rethrown to provide more information when debugging. You use the throw keyword to throw an exception, as shown in the following code:
Lecturer: Chhieng Sokha |Nguon Bunsour
100
Chapter 5: Programming with C# Exception e = new Exception(); throw e;
Exception handling Strategies
The preceding code is equivalent to: throw new Exception(); There are several strategies for handling exceptions: You can decide to ignore an exception, relying instead on the caller to handle the exception. This strategy can leave your object in an incorrect state, but it is sometimes necessary. You can catch the exception, try to fix the error, ensuring that at least your object is in a known state, and then rethrow the exception. This strategy has the advantage of leaving your object in a usable state, but it does not give the caller much useful information. You can catch the exception and add information to it by throwing a new exception that wraps around the old exception. This strategy is preferable because your object can then provide additional information about the error. This example throws an exception if the contents of a text box cannot be converted to a number, and catches FormatException. If the problem occurred because the user did not type a value, it creates a new exception that wraps up the FormatException, and adds information.
Example 4.2
private int ReadData() { byte tickets = 0; try { tickets = Convert.ToByte(textBox1.Text); } catch ( FormatException e ) { if ( textBox1.Text.Length == 0 ) { throw (new FormatException("No user input ",e)); } else { throw e; } } return tickets; } In a real application, you check the user input rather than throwing an exception. The user of the ReadData method can catch the new FormatException and retrieve the additional information provided by the object that threw the exception, as shown in the following code: private void run_Click(object sender, System.EventArgs ea) { int tickets = 0; try { tickets = ReadData(); } catch ( FormatException e ) { MessageBox.Show( e.Message + "\n" ); MessageBox.Show( e.InnerException.Message ); } }
Lecturer: Chhieng Sokha |Nguon Bunsour
101
Chapter 5: Programming with C# When the exception is caught by the run_Click method, e references the new FormatException object thrown in ReadData, so the value of e.Message is No user input. The property e.InnerException refers to the original exception, so the value of e.InnerException.Message is Input string was not in a correct format, which is the default message for FormatException.
Lecturer: Chhieng Sokha |Nguon Bunsour
102
Chapter 5: Programming with C#
Lesson 5: Delegates and Events After completing this lesson, you will be able to: Describe a delegate.
Create a delegate.
Use a delegate.
Describe an event.
Write an event handler.
What Is a Delegate? Declaring Delegates
A delegate is a variable, a reference type that can contain a reference to a method. Using delegates is useful when you know that your application must perform an action by calling a method; but, at compile time, you do not know what that action will be. You can declare a delegate using the following form: [modifiers] delegate result identifier ([parameters]) where: modifiers is a valid combination of access modifiers in addition to the new modifier. result is the type of the delegate, which is the same as the type of the encapsulated method. identifier is the delegate name. parameters is an optional list of parameters. For example: delegate void MyDelegate(object o1, object o2); This delegate can encapsulate methods with the same signature, such as: static void MyMethod(object o1, object o2) { ... }
Creating a Delegate
To create a delegate, follow these steps: 1. Declare the delegate where you usually declare types (in a namespace or a class). For example: delegate void MyDelegate(object o1, object o2);
2. Declare the method that will be associated with the delegate. For example: public static void MyMethod(object id, object name){...}
Notice that the return type and parameter types are identical for both the methods and the delegate (they are indicated by the boldface). 3. Create a delegate object: MyDelegate delegObj = new MyDelegate(MyMethod);
Notice that the parameter of the delegate is the name of the encapsulated method. You can also create a delegate object without using the new operator, simply by assigning the method to the delegate: MyDelegate delegObj = MyMethod;
Invoking the Delegate Invoke the delegate using the same parameters you would use when calling the associated method. You can invoke the delegate created in the preceding section like this: delegObj(119, "Jane Doe"); Alternatively, you can invoke the delegate from a method, as shown in the following example: Lecturer: Chhieng Sokha |Nguon Bunsour
103
Chapter 5: Programming with C# public static void CallDelegate(MyDelegate meth) { meth(119, "Jane Doe"); } Notice that this method is using a parameter, meth, of the type MyDelegate. It is obvious that the name of the method is not important, but the signature is; it must have the same signature as the encapsulated method, MyMethod. You can also invoke the delegate by using the .NET method Invoke like this: delegObj.Invoke(119, "Jane Doe");
In this specific example, we used the modifier static, just to make things simpler. However, delegates can use both instance and static methods. In the following example, delegates are brought into action. Example // UsingDelegates.cs using System; // Declare a delegate: delegate void MyDelegate(int n, string s); class MainClass { static void Main() { // Instantiate the class: MyClass obj = new MyClass(); // Instantiate the delegate: MyDelegate d = new MyDelegate(obj.MyMethod); // Invoke the delegate: obj.CallDelegate(d); } } class MyClass { // A method to invoke the delegate: public void CallDelegate(MyDelegate meth) { meth(119, "Jane Doe"); } // The encapsulated method: public void MyMethod(int id, string name) { Console.WriteLine("ID = {0}\nName = {1}", id, name); Console.ReadLine(); } }
Output: ID = 119 Name = Jane Doe What Is a event?
An event is an action that you can respond to, or handle, in code. Events can be generated by a user action, such as clicking a button with the mouse or pressing a key. Events can also be programmatically generated. The primary use of multicasting is to handle events by using program code or the operating system.
Types of events
The types of events that are raised by an object vary, but many types of events are common to most controls. For example, most objects handle a Click eventâ&#x20AC;&#x201D;when a user clicks a form, code in the Click event handler of the form is executed. The most commonly used events are keyboard, mouse, and property events. If your application supports drag-and-drop operations, it will handle drag-and-drop events. Several events are related to the user's use of the mouse and keyboard. Each of these events has an event handler for which you can write code in your
Mouse and keyboard events
Lecturer: Chhieng Sokha |Nguon Bunsour
104
Chapter 5: Programming with C# Windows-based applications. These events include MouseDown, MouseUp, MouseMove, MouseEnter, MouseLeave, MouseHover, KeyPress, KeyDown, and KeyUp. The mouse-related event handlers receive an argument of type EventArgs, which contain data related to their events. The key-related event handlers receive an argument of type KeyEventArgs, which contains data related to their events. Property events
Property events occur when a property changes. For example, a control can register to receive a SizeChanged event when its Size property changes.
Delegates as event handlers
The .NET framework event model uses delegates to bind events to the methods that are used to handle them. The delegate allows other classes to register for event notification by specifying a handler method. When the event occurs, the delegate calls the bound method or methods. The method that is called when the event occurs is referred as the event handler. The most common use of events in the .NET Framework is to handle activity in the user interface.
Receiving an event
The easiest way to register to receive events is to use the Visual Studio .NET development environment. The Properties window in the development environment contains an Events icon, as shown below: Clicking this icon displays a list of events that can be sent from the selected object.
When you double-click the name of an event, the development environment creates an event handler for that event. The following code, which is generated in the initialization method, adds the button1_Click method to the delegate: this.button1.Click += new System.EventHandler(this.button1_Click);
Visual Studio .NET inserts the button1_Click method into the code, and you place your event-handling code in this method: private void button1_Click(object sender, System.EventArgs e) { }
Lecturer: Chhieng Sokha |Nguon Bunsour
105
Chapter 5: Programming with C# The sender parameter passes a reference to the object that caused the event. In the preceding example, this is a reference to the button1 object. The System.EventArgs class contains useful information about the event. Certain events pass a specific EventArgs class. For example, the MouseUp, MouseDown, and MouseMove events pass a MouseEventArgs object to the subscribed event handler. The MouseEventArgs class defines the X and Y position of the mouse, in addition to button click and mouse wheel information. Example
The following example shows how to handle mouse events. This Windows form displays the current coordinates of the mouse when the left mouse button is held down. As the mouse moves, the coordinates are updated. When the button is released, the display is cleared.
The text box is named textBox1. Three event handlers are registered for the form (Form1), one each for MouseDown, MouseUp, and MouseMove event. When the mouse button is pressed, a MouseDown event is sent to the handler, which sets a Boolean variable tracking to true. When the mouse is moved, the MouseMove event handler is called. If tracking is set to true, this handler updates the display with the current mouse position. When the button is released, the MouseUp event handler is called, which sets tracking to false and clears the display. The event-handling code follows: private bool tracking = false; string coordinateDisplay = null; private void Form1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e) { tracking = true; } private void Form1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e) { tracking = false; textBox1.Clear(); } private void Form1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) { if (tracking) { coordinateDisplay = "X: " + e.X + " textBox1.Text = coordinateDisplay;
Lecturer: Chhieng Sokha |Nguon Bunsour
Y:" + e.Y;
106
Chapter 5: Programming with C# } }
The following code registers the event handlers (this is Form1): this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown); this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseUp); this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
MouseEventHandler is the delegate type that is declared in the Forms class, and MouseDown, MouseUp, and MouseMove are the Forms class delegates that provide the event notification.
Lecturer: Chhieng Sokha |Nguon Bunsour
107
Norton University| DCS, Y2
Chapter 6: Building .NET-based Applications with C# Contents Lesson 1: Examining the .NET Framework (109) Lesson 2: Overriding Methods from System.Obect (112) Lesson 3: Formatting Strings and Numbers (116) Lesson 4: Using Streams and Files (119)
Chapter 6: Building .NET-based Applications with C#
Lesson 1: Examining the .NET Framework Class Library This tutorial is divided into the following sections:
.NET Framework Class Library
The Object Browser
Introduction
Classes in the .NET Framework class library are arranged into a hierarchy of namespaces. For example, all of the classes for data collection management are in the System.Collections namespace.
Common .NET Framework class library namespaces
Some of the most common namespaces in the .NET Framework class library are described in the following table.
Namespace System
Description Contains fundamental classes and base classes that define commonlyused value and reference data types, events and event handlers, interfaces, attributes, and processing exceptions. System.Data Contains most of the classes that constitute the Microsoft ADO.NET architecture. The ADO.NET architecture enables you to build components that manage data from multiple data sources. System.Drawing Provides access to the Graphical Device Interface (GDI+) functions. More advanced functions are provided in the System.Drawing.Drawing2D, System.Drawing.Text, and System.Drawing.Imaging namespaces. GDI+ is the set of classes that you use to produce any sort of drawing, graph, or image. System.Windows.Forms Contains classes for creating applications based on Microsoft Windows®. System.Web.Services Contains the classes that you use to build and use XML Web Services. System.Web.UI Contains classes and interfaces that allow you to create controls and pages that will appear in your Web applications as user interface on a Web page. System.Collections Contains interfaces and classes that define various collections of objects, such as lists, queues, bitarrays, hash tables, and dictionaries. System.Diagnostics Contains classes that allow you to interact with system processes, event logs, and performance counters. This namespace also provides classes that allow you to debug your application and to trace the execution of your code. System.IO Contains types that allow you to read and write files. The Object Browser
Use the Visual Studio .NET Object Browser to examine objects such as namespaces, classes, structures, interfaces, types, and object members such as properties, methods, events, and constants from projects in your solution, referenced components within those projects, and external components. Tip: To open the Object Browser by using shortcut keys, press CTRL+ALT+J.
Lecturer: Chhieng Sokha | Nguon Bunsour
109
Chapter 6: Building .NET-based Applications with C#
Object Browser elements Element Objects pane
Elements of the Object Browser are described in the following table.
Members pane
Description pane
Browse
Description Namespaces and their members are displayed in the Objects (left) pane. As you browse objects in this pane, you can display the inheritance hierarchy that makes up a particular member. If an object in the Objects pane includes members such as properties, methods, events, variables, constants, and enumerated items, those members are displayed in the Members (right) pane. This pane displays detailed information about the currently selected object or member, such as: Name and parent object. Syntax, based on the current programming language. Links to related objects and members. Description, comments, or Help text. Attributes. Not every object or member has all of this information. You can copy text from the Description pane to the editor window. This element allows you to locate an object within the namespace hierarchy, or to select either the Active Project browsing scope or the Selected Components browsing scope. You can determine what components are shown by choosing and customizing the browsing scope. The Active Project browsing scope is the contents of the active project and its referenced components. The Object Browser updates as the active project changes. The Selected Components browsing scope allows you to choose specific components to browse. These components can include projects in your solution and their referenced components, and any other external components, such as .NET Framework components.
Lecturer: Chhieng Sokha | Nguon Bunsour
110
Chapter 6: Building .NET-based Applications with C# Customize button
Toolbar
This button is available when you select Selected Components as your browsing scope. This displays the Selected Components dialog box where you specify the components that you want to browseâ&#x20AC;&#x201D; projects and their referenced components, and external components. This element allows you to specify and customize the browsing scope, sort and group the contents of the Object Browser, move around within it, and search for symbols by using the Find Symbol dialog box.
Note You can also use Class View to view projects in your solution. Class View gives you a hierarchical view of symbols restricted to only the projects in your solution. You can use Class View to discover and edit the structure of your code and the relationships between objects in it. To use Class View, in Visual Studio .NET, on the View menu, click Class View, or press CTRL+ALT+C.
Lecturer: Chhieng Sokha | Nguon Bunsour
111
Chapter 6: Building .NET-based Applications with C#
Lesson 2: Overriding Methods from System.Object After completing this lesson, you will be able to: ď&#x201A;§
Name the methods that are inherited from the Object class.
ď&#x201A;§
Override and implement the ToString method.
Introduction
Every object in the .NET Framework inherits from the System.Object base class. This class implements a small number of methods that are available on all objects. These methods are ToString, GetHashCode, Equals, and GetType. When you create a new class, the new class inherits these methods.
Overriding methods
The default implementation of Object class methods may not provide the function that you need for your new class, requiring you to override the method. Generally, only the ToString, GetHashCode, and Equals are overridden.
ToString method
The ToString method creates and returns a human-readable text string that describes an instance of the class. The following code demonstrates how to call the ToString method: object o = new object(); MessageBox.Show(o.ToString());
GetHashCode method
The GetHashCode method returns an integer number as a hash code for the object. Other .NET Framework class library classes and .NET-compatible languages such as C# use this method to quickly locate instances of an object when the object is contained in a hash table. For example, the C# statement switch, uses a hash table that is populated with hash entries from the GetHashCode method to improve the efficiency of the statement.
Equals method
The Equals method determines whether two objects are equal. The following code demonstrates how to call the Equals method: object o1 = new object(); object o2 = o1; MessageBox.Show(o1.Equals(o2).ToString());
GetType method
The GetType method obtains the type of the current instance. The following code demonstrates how to call the GetType method: object o = new object(); MessageBox.Show(o.GetType().FullName); It is unlikely that you would ever override the GetType method. It is included here because it is inherited from the System.Object class.
Example 2.1 using System; public class Employee { public string firstName; public string lastName; public Employee(string firstName, string lastName) { this.firstName = firstName; this.lastName = lastName; }
Lecturer: Chhieng Sokha | Nguon Bunsour
112
Chapter 6: Building .NET-based Applications with C# public void Display() { Console.WriteLine("firstName = " + firstName); Console.WriteLine("lastName = " + lastName); } public static Employee Copy(Employee Employee) { return (Employee)Employee.MemberwiseClone(); } } class methodsInherited { public static void Main() { Console.WriteLine("Creating Employee objects"); Employee myEmployee = new Employee("A", "M"); Employee myOtherEmployee = new Employee("B", "N"); Console.WriteLine("myEmployee details:"); myEmployee.Display(); Console.WriteLine("myOtherEmployee details:"); myOtherEmployee.Display();
}
Console.WriteLine("myEmployee.ToString() = " + myEmployee.ToString()); Console.WriteLine("myEmployee.GetType() = " + myEmployee.GetType()); Console.WriteLine("myEmployee.GetHashCode() = " + myEmployee.GetHashCode()); Console.WriteLine("Employee.Equals(myEmployee, myOtherEmployee) = " + Employee.Equals(myEmployee, myOtherEmployee)); Console.WriteLine("Employee.ReferenceEquals(myEmployee, myOtherEmployee) = " + Employee.ReferenceEquals(myEmployee, myOtherEmployee));
}
Output Creating Employee objects myEmployee details: firstName = A lastName = M myOtherEmployee details: firstName = B lastName = N myEmployee.ToString() = Employee myEmployee.GetType() = Employee myEmployee.GetHashCode() = 58225482 Employee.Equals(myEmployee, myOtherEmployee)= False Employee.ReferenceEquals(myEmployee, myOtherEmployee)= False
More Examples http://www.java2s.com/Tutorial/CSharp/0140__Class/0940__System.Object.htm
Override the ToString Method
Every object in C# inherits the ToString method, which returns a string representation of that object. For example, all variables of type int have ToString method, allowing them to return their contents as a string:
Lecturer: Chhieng Sokha | Nguon Bunsour
113
Chapter 6: Building .NET-based Applications with C# int x = 42; string strx = x.ToString(); System.Console.WriteLine(strx); The following code contains a Car class with two public fields. The code under the class writes to the console the output from the default ToString method that was inherited from the System.Object object. Example 2.2
public enum CarSize { Large, Medium, Small, } public class Car { public CarType
Size;
public int TopSpeed; } Car myCar = new Car(); myCar.Size = CarSize.Small; MessageBox.Show(myCar.ToString()); The preceding line of code writes the name of the executing object to the console as follows: WindowsApplication1.Form1.Car Overriding the ToString method
However, if you need the ToString method to produce the size of the car instead of the Car class name, you must override the default ToString method, as shown in the following code: public override string ToString() { return ( this.Size.ToString() + " Car"); } Using ToString on the Car class now produces the following output: Small Car This output is written to the console for the instance that was created in the preceding example.
Tip: To override the OnString method in your class or struct:
1. Declare a ToString method with the following modifiers and return type: public override string ToString(){} 2. Implement the method so that it returns a string. The following example returns not only the name of the class, but also the data specific to a particular instance of the class. Note that it also uses theToString method on the age variable to covert the int to a string that can be output. class Person { string name; Lecturer: Chhieng Sokha | Nguon Bunsour
114
Chapter 6: Building .NET-based Applications with C# int age; SampleObject(string name, int age) { this.name = name; this.age = age; } public override string ToString() { string s = age.ToString(); return "Person: " + name + " " + s; } }
Lecturer: Chhieng Sokha | Nguon Bunsour
115
Chapter 6: Building .NET-based Applications with C#
Lesson 3: Formatting Strings and Numbers After completing this lesson, you will be able to:
How to Format Numbers
How to Format Date and Time
Formatting numbers
Number formatting is culture dependant. For example, formatting a currency string on my laptop will return a result like £9.99, formatting a currency on a machine set for the US region would return $9.99.
Pacifier c d
Type currency decimal (whole number) exponent / scientific fixed point general number round trippable hexadecimal
e f g n r x
Format {0:c} {0:d}
Output (double 1.2345) £1.23 System.FormatException
Output ( int -12345) -£12,345.00 -12345
{0:e} {0:f} {0:g} {0:n} {0:r} {0:x4}
1.234500e+000 1.23 1.2345 1.23 1.23 System.FormatException
-1.234500e+004 -12345.00 -12345 -12,345.00 System.FormatException ffffcfc7
Custom number formatting Specifier 0 # . , %
Type zero placeholder digit placeholder decimal point placeholder thousand separator percentage
Format {0:00.000} {0:#.##} {0:0.0} {0:0,0} {0:0%}
Output (double 1234.56) 1234.560 1234.56 1234.6 1,235 123456%
In addition there is the group separator; this is useful for varying the format, depending on the value of the parameter passed. For example String.Format("{0:£#,##0.00;(£#,##0.00);Nothing}", value); This will output "£1,240.00" if passed 1243.56. It will output the same format bracketed if the value is negative "(£1,240.00)", and will output the string "Nothing" if the number is zero. Custom DateTime Formatting
There are following custom format specifies y (year), M (month), d (day), h (hour 12), H (hour 24), m (minute), s (second), f (second fraction), F (second fraction, trailing zeroes are trimmed), t (P.M or A.M) and z (time zone). Following examples demonstrate how are the format specifies rewritten to the output.
DateTime dt = new DateTime(2008, 3, 9, 16, 5, 7, 123); String.Format("{0:y String.Format("{0:M String.Format("{0:d String.Format("{0:h
yy MM dd hh
yyy yyyy}", MMM MMMM}", ddd dddd}", H HH}",
dt); dt); dt); dt);
String.Format("{0:m mm}", dt); String.Format("{0:s ss}", dt); String.Format("{0:f ff fff ffff}", dt);
Lecturer: Chhieng Sokha | Nguon Bunsour
// // // //
"8 "3 "9 "4
08 03 09 04
008 2008" Mar March" Sun Sunday" 16 16"
// "5 05" // "7 07" // "1 12 123 1230"
year month day hour 12/24 minute second
116
Chapter 6: Building .NET-based Applications with C# String.Format("{0:F FF FFF FFFF}", dt); String.Format("{0:t tt}",
dt);
String.Format("{0:z zz zzz}",
dt);
sec.fraction // "1 12 123 123" without zeroes // "P PM" A.M. or P.M. // "-6 -06 -06:00" time zone
You can use also date separator / (slash) and time sepatator : (colon). These characters will be rewritten to characters defined in the current DateTimeForma tInfo.DateSepa rator andDateTimeForma tInfo.TimeSepa rator.
// date separator in german culture is "." (so "/" changes to ".") String.Format("{0:d/M/yyyy HH:mm:ss}", dt); // "9/3/2008 16:05:07" – english (en-US) String.Format("{0:d/M/yyyy HH:mm:ss}", dt); // "9.3.2008 16:05:07" – german (de-DE)
Here are some examples of custom date and time formatting:
// month/day numbers without/with leading zeroes String.Format("{0:M/d/yyyy}", dt); // "3/9/2008" String.Format("{0:MM/dd/yyyy}", dt); // "03/09/2008" // day/month names String.Format("{0:ddd, MMM d, yyyy}", dt); String.Format("{0:dddd, MMMM d, yyyy}", dt); 2008" // two/four digit year String.Format("{0:MM/dd/yy}", dt); String.Format("{0:MM/dd/yyyy}", dt);
Standard DateTime Formatting
// "Sun, Mar 9, 2008" // "Sunday, March 9,
// "03/09/08" // "03/09/2008"
In DateTimeForma tInfo there are defined standard patterns for the current culture. For example property ShortTimePattern is string that contains value h:mm tt for en-US culture and value HH:mm for de-DE culture. Following table shows patterns defined in DateTimeForma tInfo and their values for en-US culture. First column contains format specifiers for the String.Format method.
Specifier
m, M y, Y r, R
DateTimeFormatInfo property ShortTimePattern ShortDatePattern LongTimePattern LongDatePattern (combination of D and t) FullDateTimePattern (combination of d and t) (combination of d and T) MonthDayPattern YearMonthPattern RFC1123Pattern
s
SortableDateTi mePattern
u
UniversalSorta bleDateTimePat tern
t d T D f F g G
Pattern value (for en-US culture) h:mm tt M/d/yyyy h:mm:ss tt dddd, MMMM dd, yyyy dddd, MMMM dd, yyyy h:mm tt dddd, MMMM dd, yyyy h:mm:ss tt M/d/yyyy h:mm tt M/d/yyyy h:mm:ss tt MMMM dd MMMM, yyyy ddd, dd MMM yyyy HH':'mm':'ss 'GMT' (*) yyyy'-'MM''dd'T'HH':'mm':'ss (*) yyyy'-'MM'-'dd HH':'mm':'ss'Z' (*)
(*) = culture independent
Lecturer: Chhieng Sokha | Nguon Bunsour
117
Chapter 6: Building .NET-based Applications with C# Following examples show usage of standard format specifiers in String.Format method and the resulting output. String.Format("{0:t}", String.Format("{0:d}", String.Format("{0:T}", String.Format("{0:D}", String.Format("{0:f}",
dt); dt); dt); dt); dt);
// // // // //
String.Format("{0:F}", dt);
//
String.Format("{0:g}", dt);
//
String.Format("{0:G}", dt);
//
String.Format("{0:m}", dt); String.Format("{0:y}", dt); String.Format("{0:r}", dt);
// // //
String.Format("{0:s}", dt);
//
String.Format("{0:u}", dt);
//
Lecturer: Chhieng Sokha | Nguon Bunsour
"4:05 PM" ShortTime "3/9/2008" ShortDate "4:05:07 PM" LongTime "Sunday, March 09, 2008" LongDate "Sunday, March 09, 2008 4:05 PM" LongDate+ShortTime "Sunday, March 09, 2008 4:05:07 PM" FullDateTime "3/9/2008 4:05 PM" ShortDate+ShortTime "3/9/2008 4:05:07 PM" ShortDate+LongTime "March 09" MonthDay "March, 2008" YearMonth "Sun, 09 Mar 2008 16:05:07 GMT" RFC1123 "2008-03-09T16:05:07" SortableDateTime "2008-03-09 16:05:07Z" UniversalSortableDateTime
118
Chapter 6: Building .NET-based Applications with C#
Lesson 4: Using Streams and Files After completing this lesson, you will be able to:
Introduction
Read and write text files.
Read and write binary files.
Traverse the Windows file system. In a programming context, various definitions of stream exist. Some say ‘A stream is an object used to read and write data to and from some data source (e.g., file memory, network, device, etc)’. Some say ‘A stream is an abstraction of a sequence of bytes, like a file’. I perceive a stream as a data channel having two ends; one is attached to the data source while the other is attached to the reader or writer of the data. The data source can be a file, data in memory or data on another PC. We use File Streams, Memory Streams and Network Streams to read/write data to and from these data sources. Hence, the basic functionality of any stream is to allow data to be read from and written to the data source.
An overview of the different types of streams There are many different data sources. Data can be read from files stored on a disk, on a remote PC, in memory or from some other I/O device. As developers we need a simple clean interface to access data from these many data sources using simple methods like Read() and Write(). We don’t want to go into the lower level details, such as how a data source is accessed and how data is retrieved and saved to the data source, and in which format. Streams provide exactly these features. Dot Net provides different classes to serve as different types of stream. The base class of all the streams in the .Net framework is System.IO.Stream. If you want to access data in a file you may use System.IO.FileStream, if you want to access data in memory, you may use System.IO.MemoryStream, and if you want to connect to a remote PC, you may use System.Net.Sockets.NetworkStream. The best thing about the Stream architecture in .Net is that you don’t need to worry about how data is actually read from a local file system, network socket or memory; all you need to do is to instantiate the stream object by defining the data source to connect to and then call the simple Read() and Write() methods. We have been using Console.WriteLine() and Console.ReadLine() methods right from the start. In fact, the System.Console class represents the input, output and error stream to the console window. By calling the Write() method on the Console stream, we can send the data (bytes) to the console window. The System.Stream class – the base of all streams in the .Net framework The System.Stream is an abstract class which all other streams in the .Net framework inherit. It exposes some properties and methods overridden by the concrete stream classes (like FileStream, NetworkStream, etc). A review of some of its more interesting properties and methods is provided in the following table: Member CanRead CanWrite
Description Returns a Boolean value indicating whether the stream can read from the data source. Returns a Boolean value indicating whether the stream can write to the data source.
Lecturer: Chhieng Sokha | Nguon Bunsour
119
Chapter 6: Building .NET-based Applications with C# Length Position Close() Flush() Seek() Read(byte[] buffer, int offset, int count)(Return type: int) ReadByte()
Returns the length or number of bytes in the current stream. Gets/Sets the current position of the stream. Any read/write operation on the stream is carried out at the current position. Closes the stream. Writes all the data stored in the stream buffer to the data source. Sets the current position of the stream. Reads the specified number of bytes from the current position of the stream into the supplied array of bytes and returns the number of bytes actually read from the stream Reads a single byte from the current position of the stream and returns the byte casted into an int. The ‘-1’ return value indicates the end of the stream of data. Writes the specified number of bytes at the current position of the stream from the supplied array of bytes.
Write(byte[] buffer, int offset, int count)(Return type: void) WriteByte() Writes a single byte at the current position of the stream. Different types of file streams – Reading and Writing to files The major topic of this section is about file streams, which are used to read from and write to files. There are various classes in the .Net framework that can be used to read and write files. You can simply use System.IO.FileStream to read/write bytes to the file. Alternatively you may use the System.IO.BinaryReader and System.IO.BinaryWriter classes to read binary data as primitive data types. And you can also use the System.IO.StreamReader and System.IO.StreamWriter classes to read/write text files. We will demonstrate each of these one by one. Using System.IO.FileStream to read and write data to files The System.IO.FileStream class inherits the System.IO.Stream class to provide core stream functionality to read and write data to files. It implements all of the abstract members of the Stream class to work with files. Before using any of the stream operations, we need to use the System.IO namespace in our project using System; using System.IO; We can instantiate the FileStream class in many different ways. We may use any of the File.Open(), File.OpenRead() and File.OpenWrite() methods of the System.IO.File class. FileStream fs = File.Open("C:\\C-sharp.txt", FileMode.Open);
You may also use the FileInfo class’ Open(), OpenRead() and OpenWrite() methods. FileInfo objFileInfo = new FileInfo("C:\\C-sharp.txt"); FileStream fs = objFileInfo.Open(FileMode.Open);
Finally you may use any of the number of overloaded constructors of the FileStream class. When creating any file stream, we may define four parameters. A string representing the path and name of the file A FileMode enumeration instance that defines how the operating system should open the file. The possible values include Open, OpenOrCreate, Append, Create and others. If FileMode is Open, it will attempt to open the existing file. If FileMode is OpenCreate it will attempt to open the existing file; if no file exists, it will create the new one. In Append file mode, the new data will be written at the end of the existing file. A FileAccess enumeration instance defines which operations are allowed during the file access. The possible values include Read, Write and ReadWrite. If FileAccess is Read, you can only read from the file stream. A FileShare enumeration instance that defines the sharing options for the file. The possible values include None, Read, ReadWrite, Write. If FileShare is None, Lecturer: Chhieng Sokha | Nguon Bunsour
120
Chapter 6: Building .NET-based Applications with C# no other stream can open this file until you have got this stream open. If FileShare is Read, other streams can open and only read from this file.
The code behind it is very simple. The event handler for the Read File button (btnGo) is: private void btnGo_Click(object sender, EventArgs e) { string fileName = "d:\\outline.txt"; lblFileName.Text = "File Name: " + fileName; // Open existing file in Read only mode without allowing any sharing FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None); // create an array of bytes of the size of file\ // and read file contents to it. byte[] byteText = new byte[fs.Length]; fs.Read(byteText, 0, byteText.Length); // convert bytes array to string and display in the text box txtFileText.Text = System.Text.Encoding.ASCII.GetString(byteText); // close the file stream so that other streams may use it fs.Close(); }
Here, we have used the file stream to open the existing file (FileMode.Open) in read only mode (FileAccess.Read) and without allowing any other stream to use it while our application is using this file (FileShare.None). We then created an array of bytes with length equal to the length of the file and read the file into it. fs.Read(byteText, 0, byteText.Length); Here we have specified that we want to read the file contents into the byteText array, that the file stream should start filling the array from the â&#x20AC;&#x2DC;0â&#x20AC;&#x2122; index and that it should read byteText.Length (size of file) bytes from the file. After reading the contents, we need to convert the byte array to a string so that it can be displayed in the text box. Finally, we have closed the stream (and thus the file) so that other streams may access it. Similarly, the event handler for Save File button (btnSaveFile) is: private void btnSaveFile_Click(object sender, EventArgs e) { string fileName = "d:\\outline.txt";
Lecturer: Chhieng Sokha | Nguon Bunsour
121
Chapter 6: Building .NET-based Applications with C# // Open existing file in Read only mode without allowing any sharing FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Write, FileShare.None); // covert the text (string) in the text box to bytes array // and make the byteText reference to point to that byte array byte[] byteText = System.Text.Encoding.ASCII.GetBytes (txtFileText.Text); // write the byte array to file from the start to end fs.Write(byteText, 0, byteText.Length); // close the file stream so that other streams may use it fs.Close(); }
Here we have first converted the text in the text box to a byte array and then written it to the file using FileStream class’ Write() method:
fs.Write(byteText, 0, byteText.Length); In the above line we have told the FileStream class to write the bytes in the byteText array to the associated file. We have asked it to start writing from the first byte of the array and write the complete array to the file. Using BinaryReader and BinaryWriter to read and write primitives to files The problem with using the FileStream class is that we can only read and write bytes to the file. We have to explicitly convert other types of data (int, double, bool, string) to bytes before writing to the file (and vice versa for reading). The Dot Net framework class library provides two classes that allow us to read and write primitive data types to a file. We can use System.IO.BinaryReader to read primitive data types from a file and System.IO.BinaryWriter to write primitives to the file. An important point about the BinaryReader and BinaryWriter classes is that they need a stream to be passed in their constructor. These classes use the stream to read and write primitives. Let’s create an application that writes different primitives to a file and then read them back. The application will finally look like this:
The text box in the application is read only. At first, the Read File button is also disabled and the user needs to select the Save File button to save the file first, and then read the file back to the text box. The contents written to the file are hard coded in the Save File button’s click event handler which is: private void btnSaveFile_Click(object sender, EventArgs e) { string fileName = "d:\\C-sharp.txt"; // Open existing file in Read only mode without allowing any sharing FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Write, FileShare.None); // Open the Writer over this file stream BinaryWriter writer = new BinaryWriter(fs);
Lecturer: Chhieng Sokha | Nguon Bunsour
122
Chapter 6: Building .NET-based Applications with C# // write different types of primitives to the file writer.Write("I am David\r\n"); writer.Write("Age: "); witer.Write(23); writer.Write("\r\nWeight: "); writer.Write(45.5); // close the file stream so that other streams may use it writer.Close(); fs.Close(); btnSaveFile.Enabled = true; }
Here we have first created the file stream and used it to instantiate the BinaryWriter class. We have then written different primitives to the stream using BinaryWriterâ&#x20AC;&#x2122;s Write() method, which has many overloaded versions to write different type of primitives. Finally we have closed the two streams and enabled the Load File button. This picture below show when you open it with Notepad application.
The event handler for the Load File button is: private void btnGo_Click(object sender, EventArgs e) { string fileName = "d:\\C-sharp.txt"; lblFileName.Text = "File Name: " + fileName; // Open existing file in Read only mode without allowing any sharing FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.None); // Open the Reader over this file stream BinaryReader reader = new BinaryReader(fs); // read different types of primitives to the file string name = reader.ReadString(); string ageString = reader.ReadString(); int age = reader.ReadInt32(); string wtString = reader.ReadString(); double weight = reader.ReadDouble(); // concatenate primitives into single string and display in the text box txtFileText.Text = name + ageString + age.ToString() + wtString + weight.ToString(); // close the file stream so that other streams may use it reader.Close(); fs.Close(); }
Here we create the BinaryReader classâ&#x20AC;&#x2122; object using the FileStream object. We then read the primitives previously written to the file. After reading all the data, we concatenate the primitives to a single string and display it in the text box. Finally we close the two streams. The important point to note here is that the primitives are read in the same order they were written. Lecturer: Chhieng Sokha | Nguon Bunsour
123
Chapter 6: Building .NET-based Applications with C# Working with the File System
This section is further divided into three parts. In the first part, we will see how we can get the software system’s environment information, e.g. the path to the Windows System folder & the Program Files folder, current user name, operating system version, etc. In the second part, we will learn how to perform common file operations such as copying, moving, deleting, renaming and more. In the last part of this section, we will explore directory (or Folder) manipulation techniques. The System.Environment class The System.Environment class is the base class used to obtain information about the environment of our application. The description of some of its properties and methods is presented in the following table:
Member CurrentDirectory MachineName OSVersion UserName Version
Description Gets or sets the directory name from which the process was started Gets the name of computer on which the process is currently executing Returns the version of current Operating System Returns the user name of the user executing this process Returns a System.Version object representing the complete version information of the common language runtime (CLR) Exit() Terminates the current process, returning the exit code to the Operating System GetFolderPath() Returns the complete path of various standard folders of the windows operating system like Program files, My documents, Start Menu and etc. GetLogicalDrives() Returns an array of type string containing the list of all drives present in the current system. Demonstration Application – Environment Information Let’s make a demonstration application that uses the above mentioned properties and methods to display environment information. It is a windows application project that contains a list box named ‘lbx’ which is used to display the information, a button named ‘btnGo’ which will be used to start fetching the information and a button named ‘btnExit’ which terminates the application. The main logic is present inside the Go button's event handler: private void btnGo_Click(object sender, EventArgs e) { OperatingSystem os = Environment.OSVersion; PlatformID OSid = os.Platform; string[] drives = Environment.GetLogicalDrives(); string drivesString = ""; foreach (string drive in drives) { drivesString += drive + ", "; } drivesString = drivesString.TrimEnd(' ', ','); lbx.Items.Add("Machine Name:\t" + Environment.MachineName); lbx.Items.Add("Operating System: \t" +Environment.OSVersion); lbx.Items.Add("Operating System ID:\t" + OSid); lbx.Items.Add("Current Folder: \t" + Environment.CurrentDirectory); lbx.Items.Add("CLR Version: \t" + Environment.Version); lbx.Items.Add("Present Drives: \t" + drivesString); }
Here we have simply retrieved the environment information from public properties and methods and added them to the list box. A few important things to note here are: Lecturer: Chhieng Sokha | Nguon Bunsour
124
Chapter 6: Building .NET-based Applications with C#
Environment.GetLogicalDrives() returns an array of strings, with each string representing the drive name. Environment.Version returns an object of type System.Version which contains the detailed information about the current version of the common language runtime (CLR). The event handler for exit button simply calls the Exit() method of the Environment class to terminate the current process. private void btnExit_Click(object sender, EventArgs e) { Environment.Exit(0); }
Obtaining the paths of various Windows Standard folders – Environment.GetFolderPath() The method Environment.GetFolderPath() can be used to get the complete paths of various windows standard folders on the current machine. The only argument passed to the method is a value from the System.Environment.SpecialFolder enumeration. Some of the more common members of this enumeration are: Member ProgramFiles CommonProgramFiles DesktopDirectory Favorites History Personal Programs Recent SendTo StartMenu Startup System ApplicationData CommonApplicationData LocalApplicationData Cookies
Description The program files folder where programs are usually installed The Common Files folder of Program Files. The folder representing the desktop of user The Favorites folder to store favorite links The History folder to store history files The My Documents folder The folder representing the Programs menu of Start Menu The Recent folder The Send To folder The Start menu folder Folder of the Startup menu on the Start>>Programs menu The System folder of Windows folder The Application Data folder The Common Application Data folder The Local Application Data folder The folder used to store cookies setting
private void btnGo_Click(object sender, EventArgs e) { OperatingSystem os = Environment.OSVersion; PlatformID OSid = os.Platform; string[] drives = Environment.GetLogicalDrives(); string drivesString = ""; foreach (string drive in drives) { drivesString += drive + ", "; } lbx.Items.Add("Program Files: \t" + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFil es)); lbx.Items.Add("Common Program Files:\t" + Environment.GetFolderPath (Environment.SpecialFolder.CommonProgramFiles)); lbx.Items.Add("Windows Desktop: \t" + Environment.GetFolderPath (Environment.SpecialFolder.DesktopDirectory)); lbx.Items.Add("Favorites: \t" +
Lecturer: Chhieng Sokha | Nguon Bunsour
125
Chapter 6: Building .NET-based Applications with C# Environment.GetFolderPath(Environment.SpecialFolder.Favorites) ); lbx.Items.Add("History: \t" + Environment.GetFolderPath(Environment.SpecialFolder.History)); lbx.Items.Add("Personal (My Documents:\t" + Environment.GetFolderPath(Environment.SpecialFolder.Personal)); //. . . . . . . . . . . . . . . . //. . . . . . . . . . . . . . . . }
Lecturer: Chhieng Sokha | Nguon Bunsour
126
Norton University| DCS, Y2
Chapter 7: Building .NET-based Applications with C#
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications Introdcution
Now we will start building Windows Applications in C#. We will start by looking at the architecture of Windows Application and their support in .Net. Later, we will design our first "Hello WinForm" Application and learn about various windows form controls. Finally, we will look at how Visual Studio.Net eases the creation of Windows Applications. Windows Applications C# and .Net provide extensive support for building Windows Applications. and .Net The most important point about windows applications is that they are 'event driven'. All windows applications present a graphical interface to their users and respond to user interaction. This graphical user interface is called a 'Windows Form', or 'WinForm' for short. A windows form may contain text labels, push buttons, text boxes, list boxes, images, menus and vast range of other controls. In fact, a WinForm is also a windows control just like a text box, label, etc. In .Net, all windows controls are represented by base class objects contained in the System.Windows.Forms namespace. WinForm Basics As stated earlier, .Net providesthe WinForm and other controls through base classes in the System.Windows.Forms namespace. The class System.Windows.Forms.Form is the base class of all WinForms in .Net. In order to design a windows application, we need to: 1. Create a Windows Application project in Visual Studio.Net, or add references to System.Windows.Forms and System.Drawing to your current project. If you are not using Visual Studio at all, use the /reference option of the command line compiler to add these assemblies. 2. Write a new class to represent the WinForm and derive it from the System.Windows.Forms.Form class: class MyForm : System.Windows.Form { ... }
3. Instantiate various controls, set their appropriate properties and add these to MyForm's Controls collection. 4. Write another class containing the Main() method. In the Main() method, call the System.Application.Run() method, supplying it with an instance of MyForm. class Test {
static void Main() { Application.Run(new MyForm()); }
}
The Application.Run() method registers your form as a windows application in the operating system so that it may receive event messages from the Windows Operating System. Building the "Hello WinForm" Application Let's build our first windows application, which we will call "Hello WinForm". The application will present a simple window with a "Hello WinForm" greeting at the center. The source code of the program is: using System; using System.Windows.Forms; using System.Drawing; namespace CSharpSchool { class Test { static void Main() { Application.Run(new MyWindow()); }
Lecturer: Chhieng Sokha | Nguon Bunsour
128
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications } class MyWindow : Form { public MyWindow() : base() { this.Text = "My First Windows Application"; this.Size = new Size(300, 300); Label lblGreeting = new Label(); lblGreeting.Text = "Hello WinForm"; lblGreeting.Location = new Point(100, 100); this.Controls.Add(lblGreeting); } } }
Understanding the Code At the start, we included three namespaces in our application: using System; using System.Windows.Forms; using System.Drawing;
The System namespace, as we stated in the first lesson in chapter 2, is the necessary ingredient of all C# applications. In fact, the Application class that we used later in the Main() method is defined in this namespace. The System.Windows.Forms namespaces contains the base classes for windows controls, e.g. Form, Label and Button. Finally, including the System.Drawing namespace is necessary as it contains the classes related to the drawing of controls. The Size and Point classes used later in the program are actually defined in the System.Drawing namespace. Later, we derived a new class, 'MyWindow', from the Form class defined in System.Windows.Forms. class MyWindow : Form { ... }
In the constructor of MyWindow, we specified the size and title of the form (by setting the size and text properties). The size is defined using the System.Drawing namespace's Size class. We passed two integers to the constructor of Size to specify the width and the height of the form. public MyWindow() : base() { this.Text = "My First Windows Application"; this.Size = new Size(300, 300); }
Next in the constructor, we created a text label and added it to the Controls collection of the Form. A text label is used to write some text on the form. The System.Windows.Forms.Label class defines a text label in a Windows application. We set the text of the Label using its Text property, which is of the string type. All the controls contained by a form must be added to its Controls collection; hence we have also added our label to this collection. public MyWindow() : base() { this.Text = "My First Windows Application"; this.Size = new Size(300, 300); Label lblGreeting = new Label(); lblGreeting.Text = "Hello WinForm"; lblGreeting.Location = new Point(100, 100); this.Controls.Add(lblGreeting); }
Lecturer: Chhieng Sokha | Nguon Bunsour
129
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications Finally, we have created a Test class containing the Main() method. In the Main() method, we have instantiated the MyWindow class and passed its reference to the Application.Run() method so it may receive messages from the Windows Operating System. When we execute the above code, the following screen is displayed:
To close the application, press the close button on the title bar. Adding Event Handling
Let's now add a button labeled 'Exit' to the form. The 'Exit' button will close the application when it is clicked. In .Net, Push Buttons are instances of the System.Windows.Forms.Button class. To associate some action with the button click, we need to create an event handler and register (or add) it to the Button's Click event. Below is the code for this application. using System; using System.Windows.Forms; using System.Drawing; namespace CSharpSchool { class Test { static void Main() { Application.Run(new MyWindow()); } } class MyWindow : Form { public MyWindow() : base() { // Form this.Text = "My First Windows Application"; this.Size = new Size(300, 300); this.StartPosition = FormStartPosition.CenterScreen; // Label Label lblGreeting = new Label(); lblGreeting.Text = "Hello WinForm"; lblGreeting.Location = new Point(100, 100); // Button Button btnExit = new Button(); btnExit.Text = "Exit"; btnExit.Location = new Point(180, 180); btnExit.Size = new Size(80, 30); btnExit.Click += new EventHandler(BtnExitOnClick);
Lecturer: Chhieng Sokha | Nguon Bunsour
130
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications // Adding controls to Form this.Controls.AddRange(new Control[] {lblGreeting, btnExit});
}
}
} public void BtnExitOnClick(object sender, EventArgs e) { Application.Exit(); }
In the constructor of MyWindow, first we have set certain properties of the Form. In this code, we have also used the StartPosition property of the Form, which sets the position of the form on the screen when the application starts. The type of this property is an enumeration called 'FormStartPosition'. We have set the start position of the form to the center of the screen. The new inclusion in the code is the Exit button called 'btnExit'. We have created the button using the base class System.Windows.Forms.Button. Later, we have set various properties of the button, specifically its text label (Text), its Location and its Size. Finally, we have created an event handler method for this button called BtnExitOnClick(). In the BtnExitOnClick() method, we have written the code to exit the application. We have also subscribed this event handler to the btnExit's Click event. In the end, we have added both the label and the button to the form's Controls collection. Note that this time we have used the AddRange() method of form class to add an array of controls to the Controls collection of form. This method takes an array of type Control as its parameter. When the code is run, the following window will be displayed:
Now you can press either the Exit Button or the close button at title bar to exit the application. Visual Studio.Net & its IDE (Integrated Development Environment) Most of the time, you will be using Visual Studio.Net to develop Windows applications in C#. Visual Studio.Net provides a lot of tools to help develop applications and cuts out a lot of work for the programmer. Visual Sutdio.Net provides a standard code editor and IDE for all .Net applications, along with a standard debugger, project and solution settings, form designer, integrated compiler and lot of other useful tools. IntelliSense and Hot Compiler The Visual Studio.Net IDE provides a standard text editor to write .Net applications. The text editor is loaded with IntelliSense and a hot compiler. IntelliSense gives the text editor the ability to suggest different options in the programming context. For example, when you place a dot after the name of an object, the IDE automatically provides you a list of all the members (properties, methods, etc) of the object. The following figure shows IntelliSense at work in the Visual Studio.Net IDE. Lecturer: Chhieng Sokha | Nguon Bunsour
131
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications
The hot compiler highlights the syntax errors in your program as you type the code. The following figure shows an illustration of the hot compiler at work in Visual Studio.Net.
Code Folding
One of the pleasant new features introduced in Visual Studio.Net is code folding. With code folding, you can fold/unfold the code using the + and - symbols. Usually the code can be folded/unfolded at each scope boundary (method, class, namespace, property, etc). You can also define regions within your code and can fold/unfold the code within the region. The region is defined using the #region...#endregion preprocessor directives.
Integrated Compiler, Solution builder and Debugger Visual Studio.Net provides an integrated compiler to compile and execute your application during development. You can either compile a single source file or the complete project and solution (a group of files that make up an application). Once you have compiled your application, you can debug it using the Visual Studio.Net debugger. You can even create an installer for your application using Visual Studio.Net!
Lecturer: Chhieng Sokha | Nguon Bunsour
132
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications Form Designer
Perhaps the most useful feature of the Visual Studio.Net IDE is its form designer. The form designer allows you to design the graphical user interface just by placing the controls on the form from the Toolbox. You can set a lot of properties of the form and its controls using the Properties window. The Visual Studio.Net IDE automatically writes the code in the source file as you place the controls on the form and change their properties. You can also use the IDE to create and set up the event handlers for your controls. The following figure presents an introductory view of the Visual Studio.Net Form Designer and its different supporting windows.
You can see the toolbox window at the left hand side (#1) and the properties window at the right hand side (#2) of the above snapshot. The toolbox allows you to add different controls to your form. Once the control is placed on the form, you can change its various properties from the Properties window. You can also change the location and size of the controls using the mouse. Event properties can be changed by switching to the Event Properties pane (#3) in the Properties Window. The Toolbox, Properties Window, Help Window, Solution Explorer Window, Class View Window, Output Window and other helping windows in Visual Studio IDE can be set for Docking and Auto hiding. Windows that are set for auto hide appears only when they get focus (e.g. they have mouse pointer over them or receive a mouse click), and hide when they lose focus. A window can be set for auto hide by the button marked #4 in the above figure. The hidden windows are always accessible through the left and right hand panes of the form designer window. The right hand pane is marked with #5 in the above figure and has got the class view, help and solution explorer windows in the hidden state. If some of these windows are not visible in your visual studio IDE, you can make them visible from the View menu on the standard menu bar. Writing Code for Event Handling First of all add an event handler for the Exit Button's Click event by double clicking on it in the designer. Write the following code to exit the application: private void btnExit_Click(object sender, System.EventArgs e) { Application.Exit(); }
Lecturer: Chhieng Sokha | Nguon Bunsour
133
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications When the user has selected any book, the 'Mode of Payment' group box and the Purchase button should be enabled, and if all the books are unselected, they should be disabled. This is done by writing an event handler for CheckedChanged event of the checkboxes. To add an event handler for a checkbox, either double click the checkbox in the designer or double click the 'CheckedChanged' event of checkbox in the Event property window. The CheckedChanged event of a checkbox is triggered whenever the checkbox is checked or unchecked or its Checked property is changed. Write the following code in the event handler of first checkbox: private void cbxProgCS_CheckedChanged(object sender, System.EventArgs e) { if(cbxProgCS.Checked == false && cbxProfCS.Checked == false && cbxCSSchool.Checked == false) { gbxPaymentMode.Enabled = false; btnPurchase.Enabled = false; }else{ gbxPaymentMode.Enabled = true; btnPurchase.Enabled = true; } }
In the code above if all the checkboxes are unchecked, we disable the 'Mode of Payment' group box and the Purchase button; otherwise, we enable them. Copy and paste the same code for the CheckedChanged event of the other two checkboxes (cbxProfCS and cbxCSSchool) Now execute the program and check/uncheck different checkboxes. You will notice if any of the checkboxes are checked, the Mode of Payment group box and Purchase button are enabled, and if none of the checkboxes are checked, they are disabled. Finally on the Click event of the Purchase Button, the program should display a summary containing a list of books selected, the total cost of the purchase, the mode of payment selected and any comments the user has provided. Add a Click event handler for the Purchase button by double clicking it in the designer and write the following code: private void btnPurchase_Click(object sender,System.EventArgs e) { string message = "You purchased:\r\n\t"; int amount=0; if(cbxProgCS.Checked) { amount+=20; message+=cbxProgCS.Text + "\r\n\t"; } if(cbxProfCS.Checked) { amount+=30; message+=cbxProfCS.Text + "\r\n\t"; } if(cbxCSSchool.Checked) { amount+=50; message+=cbxCSSchool.Text + "\r\n\t"; } string paymentMode=""; if(rbnFullPayment.Checked) { paymentMode = rbnFullPayment.Text; } else
Lecturer: Chhieng Sokha | Nguon Bunsour
134
Chapter 7: Creating Windowsâ&#x20AC;&#x201C;based Applications { paymentMode = rbnInstallments.Text; } message+="\r\nThe total payment due is $" + amount.ToString(); message+="\r\nThe selected mode of payment is: " + paymentMode; if(txtComments.Text != "") { message+="\r\nYour comments about us are: " + txtComments.Text; } MessageBox.Show(message, "Summary"); }
We have used three variables in the above code. The integer variable amount is used to hold the total amount of purchase, the string variable paymentMode is used to hold the selected mode of payment and the string variable message will hold the summary message that will finally be displayed in the MessageBox. First we checked each of the checkboxes and calculated the total amount; at the same time we also build the list of books selected in the string variable message. We then found the mode of payment and concatenated (added) it to the message variable. Next we concatenated the total payment and comments provided to the string variable message. Finally, we displayed the summary message in a Message Box. A message box is a dialog window that pops up with a message. A message box is a modal kind of dialog box, which means when it is displayed you cannot access any other window of your application until you have closed the message box. The MessageBox class' static Show method has many overloaded forms; the one we used takes a string to display in the message box and the title of the message box. Now when we execute the program and press the purchase button after selecting some books, we see the following output:
We hope you have started to get a good understanding of Windows applications and WinForms in this lesson. Practice is the key to success in windows programming. The more applications you design and the more experiments you perform, the better and stronger your understanding will be. No one can teach you all the properties and events of the controls. You must experiment and discover the use of these for yourself.
Lecturer: Chhieng Sokha | Nguon Bunsour
135
Chapter 7: Creating Windows–based Applications Important Points for designing Windows Applications Make your form layout simple and easy to understand. It is important that the user of your application finds it familiar. The behavior should be expected and should not surprise the user. The Format menu of the Visual Studio.Net IDE is very useful when designing the form layout. It provides a number of useful options for alignment and size of the controls. Almost all the controls have some similar properties like Location, Size, Enabled, Visible, TabIndex, etc. The TabIndex property is very important. It describes the sequence followed by the windows focus when the user presses the Tab button on the keyboard. The controls should be named so that their purpose can be recognized, e.g., we have named the Purchase button 'btnPurchase' in the previous example. Although now it is not a standard convention, it is useful to add a three letter prefix to the name of your controls so that they are recognizable by their name. Throughout the lesson, we have followed the convention by prefixing a Label control's name with lbl (lblGreeting), TextBox with txt (txtComments), Button with btn (btnPurchase), CheckBox with cbx (cbxProgCS), RadioButton with rbn (rbnFullPayment) and GroupBox with gbx (gbxPaymentMode).
Lecturer: Chhieng Sokha | Nguon Bunsour
136