Está en la página 1de 94

NGUYỄN TRẦN MINH KHUÊ

UI TP
RO

LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG


VỚI C#. NET

-1-
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 1
LẬP TRÌNH C#.NET

-2-
NGUYỄN TRẦN MINH KHUÊ

Visual C# .NET là thành viên mới nhất của dòng sản phẩm Visual Studio, đây
là ngôn ngữ lập trình mới dựa trên ngôn ngữ lập trình C/C++ nhưng mở rộng
cho phép lập trình hướng đối tượng dể dàng hơn. Cú pháp của C# tương tự như
cú pháp của ngôn ngữ lập trình C/C++ chính vì vậy rất quen thuộc với các bạn
đã có kiến thức về ngôn ngữ lập trình C/C++ hay Java.
Trong chương này chúng ta tìm hiểu về thế giới Microsoft .NET và cấu trúc
của chương trình viết bằng ngôn ngữ C#.
Các vấn đề chính sẽ được đề cập:
- Giới thiệu về Microsoft .NET.
- Cơ chế biên dịch và thực thi của chương trình .NET.
- Cấu trúc chương trình C#.
- Tạo mới hay mở ứng dụng C#.
- Biên dịch và thực thi chương trình C#.

1. GIỚI THIỆU VỀ MICROSOFT .NET


.NET được công ty Microsoft giới thiệu vào tháng 7 năm 2000, là dòng sản
phẩm bao gồm ba thành phần chính là Sản phẩm và Dịch vụ Microsoft .NET
(Microsoft .NET Products and Services), Nền .NET (.NET Platform) và Dịch vụ
của nhà cung cấp thứ 3 (3rd Party .NET Services).
1.1. .NET Platform
.NET Platform bao gồm .NET Device Software, .NET Tools and
Infrastructure, .NET User Experience, .NET Building Block Services cho phép
các ứng dụng thuộc dòng sản phẩm Microsoft .NET Products and Services có thể
chạy trên bất kỳ các thiết bị tương thích với .NET.
Ngoài ra, .NET Platform là tập các công cụ và dịch vụ dùng để phát triển
sản phẩm phần mềm thế hệ mới, thiết kế để cho phép tương tác và phối hợp
nhóm tài nguyên trên Internet.
.NET Platform dựa trên hai công nghệ chính là XML và nghi thức mạng
(Internet Protocol).
XML
XML cho phép tác dữ liệu thực từ phần trình bày, thông tin dạng mở cho
phép tổ chức, lập trình và kích hoạt dễ dàng, cho phép phân phối dữ liệu đến
nhiều thiết bị khác nhau, và cung cấp dịch vụ Web cho phép tương tác với nhiều
hệ thống khác nhau.

-3-
NGUYỄN TRẦN MINH KHUÊ

Internet Protocol
Microsoft .NET được xây dựng dựa trên những nghi thức mạng đang tồn
tại như HTTP và SOAP (Simple Object Access Prototcol). Trong đó, SOAP là
nghi thức kết từ XML/HTTP.
SOAP là nghi thức cho phép truy cập thiết bị, đối tượng và máy chủ trên
nhiều nền độc lập. Ngoài ra, nghi thức SOAP sử dụng để trao đổi thông tin giữa
các máy tính trung tâm và các máy tính vệ tinh.
.NET Platform cho phép nhà lập trình phát triển ứng dụng sử dụng các
ngôn ngữ lập trình khác nhau và chạy trên nền Windows. Hệ điều hành Windows
(CE, ME, 2000 và 2003) là tầng cuối cùng, trong khi đó tầng giữa bao gồm .NET
Framework, .NET Enterprise Servers và Building Block Services.
1.1.1. .NET Framework
NET Framework bao gồm Common Language Runtime (CLR), các lớp cơ
sở (Base classes), dữ liệu và XML (Data and XML), dịch vụ Web (Web
Services) và giao diện người sử dụng (Web UI).
1.1.2. .NET Enterprise Servers
.NET Enterprise Servers là dòng server cho phép chúng ta xây dựng và
quản lý các tương tác các hệ thống bao gồm: SQL Server 2000, Host Integration
Server, Internet Security & Acceleration Server 2000 (ISA), Exchange 2000
Server & Exchange Server 2000 Conferencing Server, Commerce Server 2000,
BizTalk Server 2000 và Application Server 2000.
1.1.3. Building Block Services
Building Block Services cung cấp các dịch vụ cho phép chúng ta tạo các
dịch vụ thương mại như Message, Calendar, Email và các dịch vụ khác.
1.2. Microsoft .NET Products and Services
Microsoft .NET Products and Services bao gồm các sản phẩm:
Windows.NET, MSN.NET, VS.NET, Office.NET và Center Server for .NET.
Trong đó, VS.NET gồm 4 ngôn ngữ lập trình chính như Visual
Basic.NET, C#, C++.NET, J# cho phép chúng ta phát triển ứng dụng Desktop
hay Web.
1.3. 3rd Party .NET Services
3rd Party .NET Services là những dịch vụ do các nhà cung cấp thứ ba phát
triển dùng để tương tác với Microsoft.NET.
2. CƠ CHẾ BIÊN DỊCH VÀ THỰC THI CỦA CHƯƠNG TRÌNH .NET
Hai ngôn ngữ lập trình chính thường được sử dụng là C++ và Visual
Basic, mã chương trình được viết và biên dịch bởi trình biên dịch (compiler) của

-4-
NGUYỄN TRẦN MINH KHUÊ

từng ngôn ngữ, mỗi ngôn ngữ có một trình thi hành (runtime) cho chính nó để
thực thi mã thực thi được tạo ra. Điều này có nghĩa là mỗi ngôn ngữ phải có trình
biên dịch và runtime cho chính nó như hình 1-1.

Runtime
C++
Executable
Code
Compiler
Code
Compiler Executed

Executable
Code
VB Runtime

Hình 1-1: Biên dịch và thực thi chương trình


Đối với .NET thì trình biên dịch của ngôn ngữ tương ứng sẽ biên dịch mã
nguồn ra một định dạng trung gian được gọi là IL (Intermediate Language) hay
MSIL (Microsoft Intermediate Language). Định dạng trung gian này thay thế
Executable Code như mô hình 1-1.
Ngoài ra, trong .NET không tốn trình runtime cho từng ngôn ngữ lập
trình, thay vào đó trình runtime thay thế bởi một trình dùng chung là CLR
(Common Language Runtime), CRL dùng để thực thi IL được rạo ra như mô tả
hình 1-2.

C#

Compiler
C Code
Compiler R Executed
IL L

VB

Hình 1-2: Biên dịch và thực thi chương trình trong .NET

Như vậy, ứng dụng viết bằng ngôn ngữ hỗ trợ .NET được biên dịch ra IL
bằng trình biên dịch tương ứng như trình bày ở trên, chúng ta nhận được tập tin
PE (Portable Executable) chứa đựng IL.

-5-
NGUYỄN TRẦN MINH KHUÊ

Biên dịch lần 2

.NET
Source IL
Code CRL

Code Machine
Biên dịch lần 1 Executed Code

Hình 1-3: Thực thi chương trình .NET

Khi chương trình được thực thi CRL biên dịch chúng ta thành mã máy
trước khi thực hiện. Điều này có nghĩa là đoạn chương trình viết trong .NET
được biên dịch hai lần và lần biên dịch thứ nhất chậm hơn lần biên dịch thứ hai
do IL được tạo ra trong lần biên dịch thứ nhất gần với mã máy như mô tả trong
hình 1-3.
Trong phần biên dịch và thực thi chương trình .NET, hai thành phần chính
là IL và CRL được trình bày như sau:
2.1. IL
IL hay MSIL là ngôn ngữ hỗ trợ thao tác giữa các thành phần, nó gần
giống với mã nhị phân và được định nghĩa như một tập lệnh dễ dàng chuyển sang
mã máy bằng CRL.
2.2. CRL
CRL là ngôn ngữ dùng để biên dịch IL ra mã máy và nó có vai trò quản lý
bộ nhớ, biên dịch một lần có thể chạy trên hệ điều hành bất kỳ hay CPU có hỗ trợ
runtime.
Lưu ý rằng, CRL for Linux đang được phát triển cho phép chương trình
của .NET có thể chạy trên máy cài đặt hệ điều hành Linux.
3. CẤU TRÚC CHƯƠNG TRÌNH C#.
Microsoft.NET được biết đến như một thế hệ dịch vụ Windows kế tiếp
và .NET Platform hỗ trợ trên 20 ngôn ngữ khác nhau. Trình biên dịch C# là một
trong những trình biên dịch hiệu qiả nhất trong dòng sản phẩm .NET.
C# xem như một ngôn ngữ lập trình thay thế C++, bởi vì nó cung cấp hầu
hết tính năng mạnh mà trước đây chỉ có trong C++. Mặc dù có nhiều ngôn ngữ

-6-
NGUYỄN TRẦN MINH KHUÊ

lập trình trong bộ .NET, nhưng C# được xem như một Platform mới cho phép
sinh viên tham khảo để phát triển ứng dụng Desktop hay Web.
Mặc khác, C# cung cấp một kỹ thuật được gọi là người thu thập cho quá
trình tìm kiếm và tự động xoá tài nguyên được chiếm bởi các đối tượng đã huỷ.
Ngoài ra, C# là ngôn ngữ lập trình hướng đối tượng hoàn toàn, thừa
hưởng lại những gì mà ngôn ngữ C/C++ đang có và tăng thêm những đặt tính
mới cho phép sử dụng lại mà vẫn giữ được tính dễ sử dụng của ngôn ngữ lập
trình Visual Basic.
Cấu trúc của class viết bằng ngôn ngữ lập trình C# như sau:
01 /* Chương trình cơ bản của C#*/
02 using System;
03 class csharp
04 {
05 static void Main(string[] args)
06 {
07 Console.WriteLine(“Hello C Sharp”); 08
Console.ReadLine();
09 }
10 }

Dòng 01 trình bày chuỗi khai báo ghi chú được đóng và mở bởi cặp dấu /*
và */.
Dòng 02 khai báo sử dụng không gian tên System bằng cách sử dụng từ
khoá using, không gian tên System chứa hầu hết các đối tượng cho phép bạn xây
dựng ứng dụng bằng C#.
Dòng 03 là tên của lớp (class) được bắt đầu bởi từ khoá class và kế đến
tên của lớp.
Dòng 04 là dấu mở đầu của một class hay phương thức.
Dòng 05 là tên của phương thức khởi động của chương trình, mỗi chương
trình viết bằng C# phải có một phương thức khởi động được gọi là Main (có thể
có tham số Main(string[] args)) thuộc thành viên static và có tầm vực là public,
chúng ta sẽ tìm hiểu các từ khoá này trong các chương kế tiếp.
Dòng 06 là dấu mở đầu của một phương thức.
Dòng 07 dùng phương thức WriteLine của đối tượng Console trong không
gian tên System để in ra chuỗi “Hello C Sharp” trên màn hình Command Prompt.
Dòng 08 dùng phương thức ReadLine của đối tượng Console trong không
gian tên System để nhận chuỗi nhập từ bàn phím trên màn hình Command
Prompt. Trong trường hợp này chờ cho người sử dụng nhấn phím enter để kết
thúc chương trình.
Dòng 09 là dấu đóng kết thúc của một phương thức.
Dòng 10 là dấu đóng kết thúc của một lớp.

-7-
NGUYỄN TRẦN MINH KHUÊ

Lưu ý rằng, class của C# có tên mở rộng là .cs, tên của tập tin của class có
thể khác với tên của class khai báo trong class. Chẳng hạn, bạn khai báo class có
tên là clsFirstCSharp nhưng tên tập tin class là Class1.cs.
4. TẠO MỚI HAY MỞ ỨNG DỤNG C#
Để viết chương trình C# bạn có thể sử dụng Visual Studio.NET hoặc dùng
một trình soạn thảo văn bản bất kỳ. Nếu như sử dụng trình Visual Studio.NET
bạn sẽ lưu dự án (project) với tên mở rộng .csproj.
Khi tạo mới project, bạn bắt đầu Start | Microsoft Visual Studio .NET
2003 | Microsoft Visual Studio .NET 2003, cửa sổ xuất hiện như hình 1-4.

Hình 1-4: Mở mới project

Nếu mở một porject đang tồn tại, bạn chọn File | Open | Project hoặc nhấn
tổ hợp phím Ctrl+Shifl + O, cửa sổ xuất hiện như hình 1-5. Bằng cách chọn tên
project trong phần File name và nhấn nút Open.
Nếu trước đó đang mở một project khác, bạn có thể mở tiếp project khác
cùng tồn tại thì chọn vào tuỳ chọn Add to Solution. Trong trường hợp bạn muốn
đóng project đang mở để mở project khác thì chọn vào tuỳ chọn Close Solution.

-8-
NGUYỄN TRẦN MINH KHUÊ

Hình 1-5: Mở project đang tồn tại

Chú ý rằng, nếu lần đầu tiên mở Visual Studio.NET thì hai tuỳ chọn Add
to Solution, Close Solution không tồn tại.
Trong trường hợp tạo mới project bạn chọn File| New | Project hoặc tổ
hợp phím Ctrl + Shifl + N, cửa sổ mở mới project xuất hiện như hình 1-6.
Bước kế tiếp, nhập vị trí lưu trữ project và tên của project trong phần
Name và Location. Nếu chọn ngôn ngữ lập trình C# thì bạn chọn vào Visual C#
Projects trong phần Project Types và loại ứng dụng trong phần Templates.
Visual Studio.NET cung cấp các loại Templates cho phép bạn tạo ứng
dụng Windows Forms (ứng dụng chạy trên máy để bàn), Class Library (tạo DLL
và COM+), ASP.NET Web Application (ứng dụng Web), ASP.NET Mobile Web
Application (ứng dụng Web trên Mobile), Console Application (ứng dụng màn
hình và bàn phím), ASP.NET Web Services (dịch vụ Web), Windows Services
(dịch vụ Windows), ...
Tương tự như trường hợp mở project đang tồn tại, nếu lần đầu tiên mở
Visual Studio.NET thì hai tuỳ chọn Add to Solution, Close Solution không tồn
tại.

-9-
NGUYỄN TRẦN MINH KHUÊ

Hình 1-6: Tạo mới porject

Lưu ý rằng, một Solution có thể có nhiều project và một hay nhiều project
trong Solution có thể là project khởi động. Để làm điều này bạn chọn vào tên
project | R-Click | Set as Startup project hoặc khai báo trong cửa sổ thuộc tính
của Solution (Project | Properties).
Bạn có thể khai báo tất cả các class chung trong một tập tin .cs thay vì một
porject, chẳng hạn sử dụng Notepad để khai báo tập tin .cs như sau:

/*tập tin twoclasses.cs */


using System;
/*class thứ nhất*/
class firstclass
{
public int lenofstring(string s)
{
return s.Length;
}
}
/*class thứ hai*/
class twoclasses
{
static void Main(string[] args)
{
string s=Console.ReadLine();
firstclass f = new firstclass();
Console.WriteLine(f.lenofstring(s));
Console.ReadLine();
}

- 10 -
NGUYỄN TRẦN MINH KHUÊ

Tuy nhiên, bạn có thể sử dụng Visual Studio.NET để tạo project, khi đó
có nhiều class thuộc một project (namespace cùng tên với tên project) như hình
1-7.

Hình 1-7: Nhiều class trong project

Khi sử dụng project để khai báo class, bạn có thể tạo một tập tin .cs với
hai class trên. Tuy nhiên trong trường hợp này có thể sử dụng hai tập tin class
trong một project và cả hai class này cùng chung một namespace (chúng ta sẽ
tham khảo trong chương không gian tên) như ví dụ sau:

/*tập tin class1.cs */


using System;
/* không gian tên*/
namespace FirstCSharp
{
/*class thứ nhất*/
class Class1
{
static void Main(string[] args)
{
string s=Console.ReadLine();
Class2 f = new Class2();
Console.WriteLine(f.lenofstring(s));
Console.ReadLine();
}
}
}

Tập tin class thứ hai

namespace FirstCSharp
{
/*Class thứ hai với tên tập tin Class2.cs*/
public class Class2
{

- 11 -
NGUYỄN TRẦN MINH KHUÊ

public int lenofstring(string s)


{
return s.Length;
}
}
}

5. BIÊN DỊCH VÀ THỰC THI CHƯƠNG TRÌNH C#


Nếu bạn muốn biên dịch từng Class, bạn có thể sử dụng tập tin csc.exe
trong cửa sổ Command Prompt như hình 1-8 với khai báo như sau:

D:\csc CSharp\ twoclasses.cs

Nếu biên dịch thành công, kết quả thông báo như sau:
Microsoft (R) Visual C# .NET Compiler
version 7.10.3052.4 for Microsoft (R)
.NET Framework version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002.
All rights reserved.

Hình 1-8: Biên dịch tập tin .cs

Trong trường hợp sử dụng Visual Studio.NET, để biên dịch project bạn
chọn vào menu có tên Build | Build Projectname. Nếu muốn biên dịch những
project trong một Solution, bạn chọn vào Build | SolutionName.
Sau khi biên dịch project thành công, trong thư mục của project xuất hiện
hai thư mục bin và obj, bạn có thể tìm thấy tập tin exe trong thư mục bin\debug
như hình 1-9.

- 12 -
NGUYỄN TRẦN MINH KHUÊ

Hình 1-9: Biên dịch project

Sau khi biên dịch thành công, bạn có thể thực thi tập tin exe này bằng
cách gọi trực tiếp từ Command Prompt hay từ Shortcut của Windows.
Tuy nhiên, trong trường hợp sử dụng Visual Studio.NET, bạn có thể chạy
thử chương trình bằng cách chọn nút Start hay F5.
Lưu ý rằng, bạn có thể mở cửa sổ Command Prompt bằng cách chọn vào
Start | Programs | Microsoft Visual Studio.NET 2003 | Visual Studio.NET Tools |
Visual Studio.NET 2003 Command Prompt.
6. KẾT LUẬN
Chương này chúng ta tìm hiểu tổng quan về Microsoft.NET và cấu trúc
của chương trình C# cùng với cách biên dịch và thực thi class hay project
trong .NET.

- 13 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 2
DỮ LIỆU TRONG C #

- 14 -
NGUYỄN TRẦN MINH KHUÊ

Kiểu dữ liệu của ngôn ngữ C# được chia ra làm hai phần chính là kiểu
giá trị (value type) và kiểu tham chiếu (reference type) và kiểu thứ ba là kiểu con
trỏ (pointers) chỉ tồn tại trong mã không bảo mật (unsafe code).
Value type khác với reference type ở chổ là value type chứa đựng dữ liệu
trực tiếp trong biến trong khi đó reference types chỉ lưu trữ tham chiếu đến dữ
liệu của nó. Với reference type, có thể có hai biến cùng tham chiếu trên cùng
một đối tượng (object), trong khi đó value type thì mỗi biến chỉ có giá trị cho
chính nó không ảnh hưởng đến biến khác.
Kiểu hệ thống của C# là object. Mọi kiểu dữ liệu trong C# đều trực tiếp
hay gián tiếp xuất phát từ kiểu lớp đối tượng.
Các vấn đề chính sẽ được đề cập:
 Kiểu dữ liệu Value.
 Kiểu dữ liệu Reference.
 Kiểu dữ liệu Pointer.
 Khái niệm Boxing và UnBoxing.
 Chuyển đổi kiểu dữ liệu.

7. KIỂU DỮ LIỆU VALUE


Kiểu giá trị là một trong hai kiểu cấu trúc (struct) hay số (enumeration).
C# cung cấp một tập các kiểu cấu trúc được gọi là kiểu đơn: value-type (struct-
type, enum-type).
 struct-type: Bao gồm type-name, simple-type, trong đó simple-type bao
gồm numeric-type và bool. Đối với numeric-type gồm có 3 loại:
 integral-type: sbyte, byte, short, ushort, int, uint, long, ulong, char.
 floating-point-type: float, double, decimal.
 enum-type: type-name.
7.1. Giá trị mặc định
Tất cả kiểu value hoàn toàn kế thừa từ lớp object. Một biến có kiểu value
luôn luôn chứa đựng thời gian có kiểu đã khai báo và giá trị mặc định được gán
mỗi khi khai báo biến có kiểu value tương ứng như sau:
 Các kiểu sbyte, byte, short, ushort, int, uint, long, and ulong có giá trị
mặc định là 0.
 char giá trị mặc định là '\x0000'.
 float giá trị mặc định là 0.0f.
 double giá trị mặc định là 0.0d.
 decimal giá trị mặc định là 0.0m.
 bool giá trị mặc định là false.

- 15 -
NGUYỄN TRẦN MINH KHUÊ

 enum-type E giá trị mặc định là 0.


 struct-type giá trị mặc định tương ứng với các trường (field) bên trong
struct tương ứng.
7.2. Kiểu struct
Kiểu struct là kiểu value bao gồm khai báo constants, fields, methods,
properties, indexers, operators, instance constructors, static constructors và các
kiểu lồng khác. Chẳng hạn khai báo struct như sau:
public struct Inventory
{
public string Item;
public int unitPrice;
public int Quantity;
public int TotalPrice;
public string DateRcvd;
public string Supplier;
}
7.3. Kiểu đơn
C# cung cấp một tập kiểu cấu trúc xác định trước được gọi là kiểu simple.
Những kiểu đơn này được nhận dạng bởi các từ khoá dành riêng và được sd bí
danh cho trước của không gian tên System như sau:
 sbyte System.SByte
 byte System.Byte
 short System.Int16
 ushort System.UInt16
 int System.Int32
 uint System.UInt32
 long System.Int64
 ulong System.UInt64
 char System.Char
 float System.Single
 double System.Double
 bool System.Boolean
 decimal System.Decimal
7.4. Kích thước và vùng giá trị
Khi sử dụng các kiểu dữ liệu trên trong C#, mỗi loại sẽ có kích thước và
vùng giá trị khác nhau.
7.4.1. Kiểu số nguyên (Integral)
C# hỗ trợ 9 kiểu số nguyên: sbyte, byte, short, ushort, int, uint, long, ulong
và char với kích thước và vùng giá trị tương ứng như sau:

- 16 -
NGUYỄN TRẦN MINH KHUÊ

 sbyte trình bày số nguyên có dấu 8-bit với giá trị trong khoảng –128 và
127.
 byte trình bày số nguyên không dấu 8-bit với giá trị trong khoảng 0 và
255.
 short trình bày số nguyên có dấu 16-bit với giá trị trong khoảng –32768
và 32767.
 ushort trình bày số nguyên không dấu 16-bit với giá trị trong khoảng 0
và 65535.
 int trình bày số nguyên có dấu 32-bit với giá trị trong khoảng –
2147483648 và 2147483647.
 uint trình bày số nguyên không dấu 32-bit với giá trị trong khoảng 0 và
4294967295.
 long trình bày số nguyên có dấu 64-bit với giá trị trong khoảng –
9223372036854775808 và 9223372036854775807.
 ulong trình bày số nguyên không dấu 64-bit với giá trị trong khoảng 0
và 18446744073709551615.
 char trình bày số nguyên không dấu 16-bit với giá trị trong khoảng 0 và
65535.
7.4.2. Kiểu dấu chấm động
C# hỗ trợ hai kiểu dấu chấm động (floating point) là: float và double dùng
để trình bày dữ liệu 32-bit cho phần chẳn và 64-bit cho phền lẻ:
 Float trình bày giá trị trong khoảng 1.5 × 10-45 đến 3.4 × 1038 với độ
chính xác 7 con số.
 double trình bày giá trị trong khoảng 5.0 × 10-324 đến 1.7 × 10308 với độ
chính xác 15-16 con số.
7.4.3. Kiểu decimal
Kiểu decimal có kích thước 128-bit phù hợp cho dữ liệu định dạng và tính
toán trong tài chính và tiền tệ. Giá trị trình bày trong khoảng 1.0 × 10 -28 xấp xỉ
đến 7.9 × 1028 với 28-29 con số
7.4.4. Kiểu bool
Kiểu bool dùng để trình bày số luận lý true hay false.
7.4.5. Kiểu enumeration
Kiểu enumeration bao gồm byte, sbyte, short, ushort, int, uint, long hay
ulong. Enumeration được định nghĩa thông qua khai báo enum.

- 17 -
NGUYỄN TRẦN MINH KHUÊ

8. KIỂU DỮ LIỆU REFERENCE


Kiểu reference là một kiểu lớp (class), đối tượng, chuỗi (string), giao tiếp
(interface), mảng (array) hay delegate.
8.1. Class types
Kiểu class được định nghĩa là một cấu trúc dữ liệu chứa các thành viên dữ
liệu bao gồm: hằng (constants) và trường (fields); thành viên hàm bao gồm
phương thức (methods), thuộc tính (properties), biến cố (events), chỉ mục
(indexers), toán tử (operators), constructors, destructors và ác kiểu lồng khác và
hỗ trợ tính kế thừa (inheritance).
8.2. Kiểu object
Kiểu lớp object là kiểu cơ sở của các kiểu khác. Mọi kiểu dữ liệu trong
C# đều trực tiếp hay gián tiếp có nguồn gốc từ kiểu lớp object và nó được sử
dụng bí danh từ lớp System.Object.
8.3. Kiểu string
Kiểu string là lớp được bít kín mà nó kế thừa trực tiếp từ object. Những đối
tượng của lớp string trình bày chuỗi ký tự Unicode và có bí danh từ lớp
System.String.
8.4. Kiểu Interface
Kiểu interface được định nghĩa như một khế ước với những class hay
struct được cài đặt cùng với Interface này. Một interface có thể kế thừa từ nhiều
interface cơ sở và class hay struct có thể cài đặt trong nhiều interface.
8.5. Kiểu Array
Kiểu mảng có cấu trúc dữ liệu chứa đựng 0 hay nhiều phần tử và được
truy cập thông bằng chỉ mục. Tất cả các phần tử trong mảng phải cùng kiểu dữ
liệu.
8.6. Kiểu Delegate
Kiểu delegate là cấu trúc dữ liệu mà nó tham chiếu đến một hay nhiều
phương thức, mỗi phần tử sẽ tham chiếu đến đối tượng tương ứng.
9. KIỂU DỮ LIỆU POINTER
Kiểu pointer được khai báo với dấu * ngay sau loại dữ liệu và trước tên
biến cùng với từ khoá unsafe. Tương tự như vậy khi biên dịch ứng dụng C# có sử
dụng kiểu dữ liệu pointer, bạn sử dụng tham số /unsafe như sau:

D:\csc pointer.cs /unsafe

Không giống như hai kiểu dữ liệu value và reference, kiểu pointer không
chịu sự kiểm soát của garbage collector, bởi vì garbage collector không dùng cho

- 18 -
NGUYỄN TRẦN MINH KHUÊ

kiểu dữ liệu này do chúng không biết dữ liệu mà con trỏ trỏ đến, chính vì vậy
pointer không cho phép tham chiếu đến reference hay một struct có chứa các kiểu
references và kiểu tham chiếu của pointer thuộc loại kiểu không quản lý
(unmanaged-type).
unmanaged-type là kiểu bất kỳ mà nó không thuộc kiểu reference và
không chứa đựng trường reference trong bất kỳ khai báo lồng. Nói cách khác,
unmanaged-type là một trong những kiểu sau:
 sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double,
decimal hay bool.
 enum bất kỳ.
 Pointer bất kỳ.
 Kiểu cấu trúc do người dùng định nghĩa (user-defined struct-type) chứa
đựng các trường của unmanaged-type.
Một quy luật trực quan cho sự kết hợp của kiểu pointer và reference là ám
chỉ đến kiểu objects cho phép chứa đựng pointer nhưng pointer không cho phép
chứa đựng kiểu reference. Chẳng hạn, các loại poiter như sau:
 byte* Pointer dạng byte
 char* Pointer dạng char
 int** Pointer dạng con trỏ của int
 int*[] Ponter dạng mảng một chiều với các phần tử int
 void* Pointer không có kiểu
Không giống như C/C++, khi khai báo nhiều biến pointer trên cùng một
hàng đối với C# có thể như sau:

int* pi, pj;

Ví dụ, khai báo đoạn chương trình với kiểu pointer như sau:

using System;
class pointer
{
static int value = 20;
unsafe static void F(out int* pi1,
ref int* pi2) {
int i = 10;
pi1 = &i;
fixed (int* pj = &value)
{
pi2 = pj;
}
}
unsafe static void Main() {
int* px1;
int i = 10;
int* px2 = &i;

- 19 -
NGUYỄN TRẦN MINH KHUÊ

F(out px1, ref px2);


Console.WriteLine("*px1 = {0},
*px2 = {1}",*px1, *px2);
}
}

10. BOXING VÀ UNBOXING


Boxing và unboxing là hai khái niệm chính trong hệ thống kiểu dữ liệu
của C#’. Nó cung cấp cầu nối giữa hai kiểu dữ liệu value và reference bằng cách
cho phép chuyển đổi bất kỳ giá trị từ kiểu value sang kiểu object.
10.1. Boxing
Boxing cho phép chuyển đổi kiểu value bất kỳ thành kiểu object hay kiểu
interface có cài đặt kiểu giá trị. Boxing một giá trị của kiểu value bao gồm quá
trình chỉ định một đối tượng và chép giá trị vào đối tượng đó.
10.2. Unboxing
Ngược lại với trường hợp boxing, unboxing cho phép chuyển đổi dữ liệu
kiểu object ra kiểu value bất kỳ hay kiểu interface có cài đặt các kiểu value.
Unboxing được thực hiện với quá trình kiểm tra đối tượng có giá trị hay không
sau đó chép giá trị ra khỏi đối tượng.
Chẳng hạn, khai báo ví dụ sử dụng khái niệm boxing và unboxing như
sau:

using System;
class BoxMe
{
static int v=10;
static void Main(string[] args)
{
BoxMe box=new BoxMe();
Console.WriteLine("Boxing & Unboxing");
box.takeObject(v);
object obj=v;
if (obj is int)
{
Console.WriteLine("obj contains an
int");
}
int unBox=(int) box.getObject();
Console.WriteLine("Boxing and
Unboxing:");
Console.WriteLine(unBox.ToString());
Console.ReadLine();
}

public void takeObject(object o)


{
Console.WriteLine("Boxing");
}
public object getObject()
{
return v;

}
}

- 20 -
NGUYỄN TRẦN MINH KHUÊ

11. CHUYỂN ĐỔI KIỂU DỮ LIỆU


Chuyển đổi dữ liệu là cho phép một biểu thức của kiểu dữ liệu này được
xem xét như một kiểu dữ liệu khác. Chuyển đổi có thể thuộc về dạng chuyển đổi
tuyệt đối (implicit) hay dạng thể hiện (explicit), chẳng hạn, chuyển đổi dữ liệu
giữa int và long như sau:
int a = 123;
long b = a;
// từ int sang long (implicit)
int c = (int) b;
// từ long sang int (explicit)

Bên cạnh hai cách chuyển đổi kiểu dữ liệu trên, boxing, unboxing cho
phép chuyển đổi dữ liệu kiểu object ra kiểu value bất kỳ hay kiểu interface có cài
đặt các kiểu value.
Để kiểm soát quá trình biến đối tượng dữ liệu được thực hiện hoàn hảo
hay không, cấu trúc kiểm soát ngoại lệ trong C# nên được cài đặt.
12. KẾT LUẬN
Trong chương này chúng ta tìm hiểu hai kiểu dữ liệu chính của C# là kiểu
value và reference. Cả hai kiểu dữ liệu này đều được kiểm tra bởi garbage
collector, một kiểu dữ liệu khác không chiệu sự kiểm soát của đối tượng này là
poiter.
Song song với kiểu dữ liệu, hai khái niệm boxing và unboxing cùng với
các chuyển đổi dữ liệu cũng được trình bày trong chương này.

- 21 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 3:
BIẾN

- 22 -
NGUYỄN TRẦN MINH KHUÊ

Biến tượng trưng cho vị trí lưu trữ, mỗi biến có kiểu mà dữ liệu lưu trữ trong
biến.C# là ngôn ngữ kiểu an toàn (type-safe) và trình biên dịch của C# bảo đảm
rằng giá trị lưu trữ trong biến luôn luôn có kiểu thích hợp, giá trị của biến có
thể thay đổi bằng cách sử dụng toán tử ++ và --.
Một biến phải được định nghĩa trước khi sử dụng, giá trị khởi tạo là cần
thiết khi khai báo biến để tránh trường hợp giá trị không tồn tại trong quá trình
thực thi.

Các vấn đề chính sẽ được đề cập:


 Khai báo biến.
 Giá trị mặc định.
 Biến kiểu mảng.
 Biến kiểu struct.
 Biến kiểu object.
 Tầm vực của biến.

13. KHAI BÁO BIẾN


C# định nghĩa 7 loại biến: static, instance, array elements, tham trị, tham
biến (ref), tham số output (tham trị, tham biến và tham số output sẽ trình bày
trong chương phương thức) và biến cục bộ (local). Ví dụ khai báo class với các
lại biến sau:

using System;
class variable
{
public static int x=0;
int y=10;
static void F(int[] v, int a, ref int b,
out int c) {
int i = 1;
c = a + b++;
Console.WriteLine("a={0},b={1},
c={2}",a,b,c);
for( i=0;i<v.Length;i++)
Console.WriteLine(v[i]);
}
static void Main() {
int[] myarr = new int[5];
variable my = new variable();
for(int j=0;j<myarr.Length;j++)
myarr[j]=j;
Console.WriteLine("Variable");
int aa=20; int bb=10; int cc=0;
Console.WriteLine("x = {0},y={1}",
x,my.y);
F(myarr,aa, ref bb,out cc);
}
}

Trong đó, x là biến static, y là biến instance, v[j] là phần tử mảng thứ j, a
là tham trị, b là tham biến, c là tham số output, và j và i là biến local.

- 23 -
NGUYỄN TRẦN MINH KHUÊ

13.1. Static
Một trường được khai báo với từ khoá static được gọi là biến static. Biến
static có thể truy cập trong toàn bộ class và nó tồn tại trước khi constructor
(static) được thực hiện.
Khi bạn khai báo biến static, bạn có thể truy cập chúng bất kỳ đâu
trong class, giả sử chúng ta khai báo và sử dụng biến static như sau:

using System;
class staticvariable
{
static int x=0;
static void myMethod()
{
x+=10;
Console.WriteLine("x={0}",x);
}
static void Main()
{
myMethod();
x+=10;
Console.WriteLine("x = {0}",x);
}
}

13.2. Instance
Biến không khai báo từ khoá static là biến instance. Biến instance có hai
loại, biến khai báo trong class và struct.
Khai báo biến instance trong class, để truy cập và sử dụng chúng bạn phai
khởi tạo đối tượng, chẳng hạn ví dụ sau:

using System;
class instancevariable
{
int x=10;
static void Main()
{
instancevariable my= new instancevariable();
my.x+=10;
Console.WriteLine("x = {0}",my.x);
// Console.WriteLine("x = {0}",x);
// Lỗi phát sinh khi gọi trực tiếp đến x
//
}
}

13.3. Phần tử Array


Phần tử mảng sẽ tồn tại khi mảng được tạo ra, các phần tử tồn tại liên tục
và có giá trị mặc định tương ứng với kiểu dữ liệu của phần tử. Ví dụ, chúng ta
khai báo như sau:

- 24 -
NGUYỄN TRẦN MINH KHUÊ

using System;
class Class1
{
static void Main(string[] args)
{
Console.Write("Enter number of array: ");
int ptu= Convert.ToInt16(Console.ReadLine());
int[] myarr = new int[ptu];
int i=0;
for (i = 0;i<ptu;i++)
{
Console.Write("array[" + i.ToString() + "]=");
myarr [i]= Convert.ToInt16(Console.ReadLine());
}
for (i = 0;i<ptu;i++)
{
Console.Write("array[" + i.ToString() + "]=");
Console.WriteLine(myarr [i].ToString());
}
Console.WriteLine("Mang nghich dao la: ");
for (i =ptu-1;i>=0;i--)
{
Console.Write("array[" + i.ToString() + "]=");
Console.WriteLine(myarr [i].ToString());
}
Console.ReadLine();
}
}

13.4. Biến cục bộ


Biến cục bộ được khai báo trong phương thức hoặc ngay trong phát
biểu vòng lặp for hay switch và có thể khai báo trong một khối lệnh. Ví dụ các
biến i và j trong ví dụ sau là biến cục bộ.

using System;
class localvariable
{
static void myarrays(int[] arr) {
int i = 1;
for( i=0;i<arr.Length;i++)
Console.WriteLine(arr[i]);
}
static void Main() {
int[] myarr=new int[5];
for(int j=0;j<myarr.Length;j++)
myarr[j]=j;
Console.WriteLine("Local Variable");
myarrays(myarr);
}
}

- 25 -
NGUYỄN TRẦN MINH KHUÊ

13.5. Biến cục bộ


Trong trường hợp khai báo tên biến cùng với từ khoá của kiểu dữ liệu,
chúng ta sử dụng từ khoá @ trước tên biến. Ví dụ, khai báo tên biến có tên int có
kiểu dữ liệu int như sau:

using System;
class variablekeyword
{
static int @int;
static void Main() {
@int+=10;
Console.WriteLine("Value of @int={0}", @int);
}
}

14. GIÁ TRỊ MẶC ĐỊNH


Khi khai báo biến, nếu bạn không khai báo giá trị trong qua trình thực thi
thì biến sẽ có giá trị mặc định tương ứng với kiểu dữ liệu của biến. Chẳng hạn,
biến có kiểu dữ liệu như sau sẽ có giá trị mặc định của biến tương ứng.
 Các kiểu sbyte, byte, short, ushort, int, uint, long, và ulong có giá trị
mặc định là 0.
 char giá trị mặc định là '\x0000'.
 float giá trị mặc định là 0.0f.
 double giá trị mặc định là 0.0d.
 decimal giá trị mặc định là 0.0m.
 bool giá trị mặc định là false.
 enum-type E giá trị mặc định là 0.
 struct-type giá trị mặc định tương ứng với các trường (field) bên trong
struct tương ứng.
 object có giá trị mặc định là null.
Ví dụ, chúng ta khai báo đoạn chương trình với hai biến không có giá trị
khởi tạo thì giá trị mặc định sẽ được in ra cho dù khi biên dịch bạn sẽ nhận được
thông điệp cảnh báo.

using System;
class defaultvalue
{
static int x;
static void Main() {
Console.WriteLine(
"Default Value of x={0}",x);
Console.WriteLine(
"Default Value of Array");

- 26 -
NGUYỄN TRẦN MINH KHUÊ

int[] myarr=new int[5];


for(int j=0;j<myarr.Length;j++)
Console.WriteLine(j.ToString() +"="+ myarr[j]);
}
}

Kết quả in ra như sau:


Default Value of x=0
Default Value of Array
array 0=0
array 1=0
array 2=0
array 3=0
array 4=0

15. BIẾN KIỂU MẢNG


15.1. Khai báo mảng
Khai báo biến mảng có hai cách như sau
 Khai báo và khởi tạo mảng
int[] yourarr=new int[ptu];

 Khai báo sau đó khởi tạo mảng


int[] myarr;
myarr=new int[ptu];

Ví dụ, chúng ta khai báo ví dụ với hai mảng myarr và yourarr như sau:

using System;
class array
{
static void Main(string[] args)
{
Console.Write("Please enter number of
array: ");
int ptu=
Convert.ToInt16(Console.ReadLine());
int[] myarr; myarr = new int[ptu];

int i=0;
for (i = 0;i<ptu;i++)
{
Console.Write("array[" + i.ToString()
+ "]=");
myarr [i]=
Convert.ToInt16(Console.ReadLine());
}
Console.WriteLine("Mang cua myarray: ");
for (i = 0;i<ptu;i++)
{
Console.Write("array[" + i.ToString()

- 27 -
NGUYỄN TRẦN MINH KHUÊ

+ "]=");
Console.WriteLine(myarr
[i].ToString());
}
Console.ReadLine();
}
}

 Khai báo mảng với số phần tử cho trước và khởi tạo giá trị cho các
phần tử của mảng.
int[] me={1,2,3,4,5};
Ví dụ khai báo mảng với chiều dài cho trước và khởi tạo giá trị cho
từng phần tử như sau:

using System;
class fixedarray
{
static void Main(string[] args)
{
Console.Write("Please enter number of
array: ");
int[] me={1,2,3,4,5};
int i=0;
Console.WriteLine("Mang cua me");
for (i =0;i<me.Length;i++)
{
Console.Write("array[" +
i.ToString() + "]=");
Console.WriteLine(
me [i].ToString());
}
for (i = 0;i<me.Length;i++)
{
Console.Write("array[" +
i.ToString() + "]=");
me[i]=
Convert.ToInt16(Console.ReadLine());
}

Console.WriteLine("Mang cua me: ");


for (i = 0;i<me.Length;i++)
{
Console.Write("array[" +
i.ToString() + "]=");
Console.WriteLine(
me [i].ToString());
}
Console.ReadLine();
}
}

15.2. Khai báo mảng


Khai báo hai biến mảng và gán cho nhau
yourarr=myarr;

Giả sử khai báo mảng myarr, sau đó gán giá trị cho từng phần tử của mảng
myarr, kế đến gán yourarr bằng myarr.

- 28 -
NGUYỄN TRẦN MINH KHUÊ

using System;
class assignarray
{
static void Main(string[] args)
{
Console.Write("Please enter number of
array: ");
int ptu=
Convert.ToInt16(Console.ReadLine());
int[] myarr; myarr = new int[ptu];
int[] yourarr=new int[ptu];
int i=0;
for (i = 0;i<ptu;i++)
{
Console.Write("array[" +
i.ToString() + "]=");
myarr [i]=
Convert.ToInt16(Console.ReadLine());
}
yourarr=myarr;
Console.WriteLine("Mang nghich dao la cua
myarray: ");
for (i =ptu-1;i>=0;i--)
{
Console.Write("array[" + i.ToString()
+ "]=");
Console.WriteLine(
myarr [i].ToString());
}
Console.ReadLine();
}
}

16. BIẾN KIỂU STRUCT


16.1. Khai báo biến struct
Để khai báo biến kiểu struct trước tiên khai báo kiểu struct:

public struct Inventory


{
public string Item;
public int unitPrice;
public int Quantity;
public int TotalPrice;
public string DateRcvd;
public string Supplier;
}

Sau đó, khai báo biến struct như sau:


Inventory temp;

16.2. Gán và truy cập giá trị của struct


Để gán và truy cập giá trị, chúng ta khai báo như sau:
structname.fieldname

Giả sử, khai báo struct, sau đó gán vào từng field của struct như sau:
public Inventory CreateItem()
{
Inventory temp;
Console.Write("Enter the Items Name : ");

- 29 -
NGUYỄN TRẦN MINH KHUÊ

temp.Item = Console.ReadLine();

Console.Write("Enter the Unit Price : ");


temp.unitPrice =
Convert.ToInt32(Console.ReadLine());

Console.Write("Enter the Quantity : ");


temp.Quantity =
Convert.ToInt32(Console.ReadLine());; return temp;
}

Truy cập giá trị của struct như sau:


public void DisplayItem(Inventory temp)
{
Console.WriteLine("\nItem Name = {0}",
temp.Item);
Console.WriteLine("Item Price = {0}",
temp.unitPrice);
Console.WriteLine("Item Quantity = {0}",
temp.Quantity);
Console.WriteLine("Amount = {0}",
temp.Quantity*temp.unitPrice);
}

17. BIẾN KIỂU OBJECT


Khai báo biến kiểu object cũng tương tự như cách khai báo biến với
các kiểu dữ liệu ở trên, ví dụ bạn khai báo đoạn chương trình như sau:

using System;
class Obj
{
static int i=10;
static void Main(string[] args)
{
object a=null;
a=i;
Console.WriteLine(a.ToString());
Console.ReadLine();
}
}

18. TẦM VỰC CỦA BIẾN


Tầm vực của biến được xác định dựa vào ba từ khoá chính là public,
protected và private.
18.1. Public<<
Khi biến khai báo với từ khoá public, biến này có thể truy cập bất kỳ
từ đâu, ví dụ khai báo biến public như sau:
< khai báo trong lớp này gọi ở lớp kia cũng đc

using System;
class publicvariable

- 30 -
NGUYỄN TRẦN MINH KHUÊ

{
public static int y=10;
static void Main() {
variable my = new variable();
Console.WriteLine("Variable i="+my.i);
//Console.WriteLine("Variable n="+my.n);
// n mac dinh la protection
Console.WriteLine("y={0}",y);
}
}
class variable
{
public int i=10;
//int n=10;
}

18.2. Protected <<hơn private một tí ở kế thừa>>


Khi biến khai báo với từ khoá protected, biến này có thể truy cập từ
đâu trong class hoặc những class kế thừa từ class khai báo nó.
Ví dụ bạn khai báo đoạn chương trình sau với biến có tầm vực trong class
và những class kế thừa từ class này.

using System;
class protectedvariable
{
static void Main() {
variable my = new variable();
//Console.WriteLine("Variable i="+my.i);
//Console.WriteLine("Variable n="+my.n);
// n mặc định là protection
// nên lỗi sẽ phàt sinh
my.mypro();
}
}
class variable
{
int i=10;
protected int n=10;
public void mypro() {
Console.WriteLine("Variable i="+i);
Console.WriteLine("Variable n="+n);
}
}

18.3. Private
Khi biến khai báo với từ khoá private, biến này có thể truy cập từ đâu
trong class khai báo nó.
Ví dụ bạn khai báo đoạn chương trình sau với biến có tầm vực trong class
khai báo nó.

- 31 -
NGUYỄN TRẦN MINH KHUÊ

using System;
class privatevariable
{
static void Main() {
variable my = new variable();
Console.WriteLine("Variable j="+my.j);
Console.WriteLine(my.getvalue());
//Console.WriteLine("Variable n="+my.n);
// lỗi phát sinh do n là private
}
}
class variable
{
public int j=10;
private int n=10;
public int getvalue()
{
return n;
}
}

19. KẾT LUẬN


Trong chương này chúng ta tập trung tìm hiểu loại, khai báo, tầm vực của
biến.

- 32 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 4
TOÁN TỬ VÀ BIỂU THỨC

- 33 -
NGUYỄN TRẦN MINH KHUÊ

Giống như các ngôn ngữ lập trình khac, C# có các toán tử đơn, toán tử đôi
và toán tử tam nguyên.
Dựa trên toán tử và toán hạng chúng ta xây dựng một biểu thức so sánh hay
biểu thức gán.
Các vấn đề chính sẽ được đề cập:
 Toán tử
 Biểu thức trong C#

20. TOÁN TỬ
Trong C# toán tử chia làm 3 loại như sau:
 Toán tử đơn: Toán tử đơn sử dụng một toán hạng với ký hiệu tiền tố
hay hậu tố chẳng hạn như –x hay x++.
 Toán tử đôi: Toán tử dùng cho hai toán hạng với ký hiệu toán tử ở giữa
như x + y.
 Toán tử tam nguyên là toán tử gồm 3 yếu tố. Yếu tố thứ nhất là biểu
thức và hai yêu tố còn lại là hai kết quả đúng và sai tương ứng với biểu thức true
hay false, ví dụ khai báo c? x: y, trong đó c là biểu thức, x là kết quả trả về khi
biểu thức c có giá trị là true, y là kết quả trả về khi biểu thức c có kết quả là false.
20.1. Nhóm toán tử
C# cung cấp các toán tử số học và luận lý cũng như các toán tử khác như
trình bày trong bảng sau:
 Số học: + - * / %
 Luận lý: & | ^ ! ~ && || true false
 Nối chuỗi: +
 Tăng giảm: ++ --
 Shift: << >>
 So sánh: == != < > <= >=
 Gán: = += -= *= /= %= &= |= ^= <<= >>=
 Thành viên truy cập: .
 Chỉ mục: []
 Chuyển đổi: Cast()
 Tam nguyên: ?:
 Nối vào hay loại ra: + -
 Tạo mới đối tượng: new
 Thông tin kiểu và kích thuớc: sizeof typeof

- 34 -
NGUYỄN TRẦN MINH KHUÊ

 Kiểm tra: checked, unchecked


 Địa chỉ: * -> [] &
20.2. Thứ tự ưu tiên của toán tử
Thứ tự ưu tiên của toán tử trong biểu thức được sắp xếp như sau:
 Toán tử đơn: x.y f(x) a[x] x++ x-- new typeof checked unchecked.
 Toán tử đơn: + - ! ~ ++x --x (T)x
 Nhân chia: * / %
 Shift: << >>
 So sánh: < > <= >= is as
 Bằng: == !=
 Luận lý: & ^ | && ||
 Tam nguyên: ?:
 Gán: = *= /= %= += -= <<= >>= &= ^= |=
20.3. Overload toán tử
Tương tự như ngôn ngữ lập trình C++, C# cho phépo overload các toán tử
như sau:
 Toán tử đơn: + - ! ~ ++ -- true false
 Toán tử đôi: + - * / % & | ^
 Shift: << >>
 So sánh: == != < > <= >=
21. BIỂU THỨC TRONG C#
Dựa trên toán tử biểu thức được xây dựng cùng với các toán hạng là biểu
thức điều khiển hay biểu thức gán.
21.1. Biểu thức điều khiển
Biểu thức điều khiển thường sử dụng các toán tử so sánh (== != < >
<= >=), so sánh loại dữ liệu (as is sizeof typeof).
21.1.1. Toán tử so sánh
Biếu thức sử dụng toán tử so sánh khai báo như sau:
using System;
class Test
{
public static void Main()
{
Console.WriteLine((2 + 2) != 4);

object s = 1;
object t = 1;
Console.WriteLine(s != t);

- 35 -
NGUYỄN TRẦN MINH KHUÊ

string a = "hello";
string b = "hello";

Console.WriteLine(a != b);

Console.WriteLine((object)a !=
(object)b);
}
}
21.1.2. So sánh loại dữ liệu
Biểu thức sử dụng toán tử so sánh loại dữ liệu khai báo như sau:
using System;
class Class1
{
}

class Class2
{
}

public class IsTest


{
public static void Test (object o)
{
Class1 a;
Class2 b;

if (o is Class1)
{
Console.WriteLine ("o is Class1");
a = (Class1)o;
}

else if (o is Class2)
{
Console.WriteLine ("o is Class2");
b = (Class2)o;
}

else
{
Console.WriteLine (
"o is neither Class1 nor Class2.");
}
}
public static void Main()
{
Class1 c1 = new Class1();
Class2 c2 = new Class2();
Test (c1);
Test (c2);
Test ("a string");
}
}
21.2. Biểu thức gán
Biểu thức gán dùng để gán giá trị vào biến khai báo như sau:
using System;
class Test
{
public static void Main()
{
int a = 5;

- 36 -
NGUYỄN TRẦN MINH KHUÊ

a += 6;
Console.WriteLine(a);
string s = "Micro";
s += "soft";
Console.WriteLine(s);
}
}
22. KẾT LUẬN
Trong chương này chúng ta tìm hiểu các loại toán tử và hai loại biểu thức
chính.

- 37 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 5
PHÁT BIỂU ĐIỀU KHIỂN

- 38 -
NGUYỄN TRẦN MINH KHUÊ

C# cung cấp nhiều loại phát biểu như: chọn, lặp, nhảy, kiểm tra, kiểm soát
ngoại lệ, lock và fixed. Trong mỗi phát biểu thường có một hay nhiều khai báo.
Bằng cách sử dụng toán tử và toán hạng chúng ta xây dựng một biểu thức so
sánh kết hợp với phát biểu chọn hay biểu thức gán sử dụng cho phát biểu lặp.
Các vấn đề chính sẽ được đề cập:
 Phát biểu chọn
 Phát biểu lặp
 Phát biểu nhảy
 Phát biểu kiểm soát ngoại lệ
 Phát biểu checked và unchecked
 Phát biểu lock
 Phát biểu fixed

23. PHÁT BIỂU CHỌN


Phát biểu chọn (selection statement) trong C# bao gồm các phát biểu (if,
else, switch và case).
23.1. Phát biểu if
Phát biểu if được chọn để thực hiện dựa trên giá trị trả về của biểu thức
Boolean.

if (expression)
statement

if (expression)
{
statement1
statement1
}

Trong đó
 expression là biểu thức trả về giá trị bool hay kiểu chứa đựng toán hạn
true hay false.
 statement là dòng lệnh sẽ được thực thi khi expression có giá trị là true.
Lưu ý, nếu bên trong phát biểu if có nhiều hơn một phát biểu thì các phát
biểu con đó phải được khai báo trong cặp dấu { và } và statement có thể là một
tập các phát biểu khác.
Ví dụ:
int i=10;
if (x > 10)
{
if (y > 20)
Console.Write("Statement");
}

- 39 -
NGUYỄN TRẦN MINH KHUÊ

23.2. Phát biểu else


Phát biểu else được chọn để thực hiện dựa trên giá trị trả về của biểu thức
Boolean là false.

if (expression)
statement1
else
statement2

Trong đó
 expression là biểu thức trả về giá trị bool hay kiểu chứa đựng toán hạn
true hay false.
 statement1 là dòng lệnh sẽ được thực thi khi expression có giá trị là
true.
 statement2 là dòng lệnh sẽ được thực thi khi expression có giá trị là
false.
Ví dụ:
int i=10;
if (x > 10)
{
if (y > 20)
Console.Write("Statement1");
else
Console.Write("Statement2");
}
23.3. Phát biểu switch và case
Phát biểu switch là phát biểu điều khiển nhiều chọn lựa bằng cách truyển
điều khiển đến phát biểu case bên trong.

switch (expression)
{
case constant-expression:
statement
jump-statement
[default:
statement
jump-statement]
}

Trong đó
 expression là biểu thức số nguyên hay là chuỗi.
 statement là dòng lệnh sẽ được thực thi khi expression chuyển đến case
hay default.
 jump-statement là phát biểu nhảy ra khỏi phát biểu switch.
 constant-expression nhảy đến case với giá trị chỉ định có khai báo trong
phát biểu switch.

- 40 -
NGUYỄN TRẦN MINH KHUÊ

Lưu ý, nếu bên trong phát biểu case nếu có nhiều hơn một phát biểu thì
không cho phép khai báo trong cặp dấu { và }.
Ví dụ:
using System;
class SwitchTest
{
public static void Main()
{
Console.WriteLine("Sizes: 1=Small 2=Medium 3=Large");
Console.Write("Enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch(n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
break;
}
if (cost != 0)
Console.WriteLine("Insert {0} cents.", cost);
Console.WriteLine("Thank you.");
}
}
24. PHÁT BIỂU LẶP
Phát biểu vòng lặp trong C# bao gồm do, for, foreach, in, while. Bằng
cách sử dụng phát biểu vòng lặp bạn có thể thực thi một tập lệnh nhiều lần cho
đến khi kết thúc hay gặp phát biểu thoát ra khỏi vòng lặp.
24.1. Vòng lặp do
Vòng lặp do thực thi một hay nhiều phát biểu bên trong cho đến khi biểu
thức có giá trị là false với cú pháp như sau:

do
statement
while (expression);

Trong đó:
 expression: expression dùng để kiểm tra điều kiện kết thúc vòng lặp do.
 statement: Một hay nhiều tập lệnh bên trong.
Ví dụ:

using System;
public class TestDoWhile
{

- 41 -
NGUYỄN TRẦN MINH KHUÊ

public static void Main ()


{
int x;
int y = 0;

do
{
x = y++;
Console.WriteLine(x);
}

while(y < 5);


}
}

24.2. Vòng lặp for


Vòng lặp for thực thi một hay nhiều phát biểu cho đến khi biểu thức có giá
trị là false với cú pháp như sau:

for ([initializers]; [expression]; [iterators])


statement

Trong đó:
 initializers: initializers là giá trị bắt đầu vòng lặp for.
 iterators: iterators là giá trị tăng hay giảm trong vòng lặp for.
 expression: expression dùng để kiểm tra điều kiện trả về giá trị bool kết
thúc vòng lặp for.
 statement: Một hay nhiều tập lệnh bên trong.
Ví dụ:

using System;
public class ForLoopTest
{
public static void Main()
{
for (int i = 1; i <= 5; i++)
Console.WriteLine(i);
}
}

24.3. Vòng lặp foreach và in


Vòng lặp foreach lặp lại một nhóm phát biểu cho mỗi phần tử trong mảng
hay tập đối tượng. Phát biểu dùng để duyệt qua tất cả các phần tử trong mảng hay
tập đối tượng và thực thi một tập lệnh với cú pháp như sau:

foreach (type identifier in expression)


statement

Trong đó:

- 42 -
NGUYỄN TRẦN MINH KHUÊ

 type: type là kiểu dữ liệu nhận dạng tương thích với kiểu dữ liệu của
phần tử trong mảng hay tập đối tượng.
 identifier: Biến có kiểu kahi báo type sẽ hiện thực giá trị của phần tử
trong expression.
 expression: expression là tập đối tượng hay mảng.
 statement: Một hay nhiều tập lệnh bên trong.
Ví dụ sử dụng foreach với mảng dữ liệu:

using System;
class foreacharray
{
public static void Main()
{
int odd = 0, even = 0;
int[] arr = new int [] {0,1,2,5,7,8,11};

foreach (int i in arr)


{
if (i%2 == 0)
even++;
else
odd++;
}

Console.WriteLine("Found {0} Odd Numbers,


and {1} Even Numbers.", odd, even) ;
}
}

Ví dụ sử dụng foreach với tập đối tượng:


using System;
using System.Collections;
public class foreachobject
{
public static void Main(string [] args)
{
Hashtable ziphash = new Hashtable();
ziphash.Add("98008", "Bellevue");
ziphash.Add("98052", "Redmond");
ziphash.Add("98201", "Everett");
ziphash.Add("98101", "Seattle");
ziphash.Add("98371", "Puyallup");
Console.WriteLine("Zip code City");
foreach (string zip in ziphash.Keys)
{
Console.WriteLine(zip + " "+
ziphash[zip]);
}
}
}

24.4. Vòng lặp while


Vòng lặp while thực thi một hay nhiều phát biểu bên trong cho đến khi
biểu thức có giá trị là false với cú pháp như sau:

while (expression)

- 43 -
NGUYỄN TRẦN MINH KHUÊ

statement

Trong đó:
 expression: expression dùng để kiểm tra điều kiện kết thúc vòng lặp
while.
 statement: Một hay nhiều tập lệnh bên trong.
Ví dụ:

using System;
class WhileTest
{
public static void Main()
{
int n = 1;

while (n < 6)
{
Console.WriteLine("Current value of n is {0}", n);
n++;
}
}
}

25. PHÁT BIỂU NHẢY


Phát biểu nhảy (break, continue, default, goto, return) sẽ được sử dụng khi
chương trình muốn chuyển đổi điều khiển.
25.1. Phát biểu break
Phát biểu break kết thúc phát biểu vòng lặp hay switch với khai báo như
sau:

break;

Ví dụ khai báo phát biểu break trong vòng lặp for:


using System;
class BreakTest
{
public static void Main()
{
for (int i = 1; i <= 100; i++)
{
if (i == 5)
break;
Console.WriteLine(i);
}
}
}

Ví dụ khai báo phát biểu break trong phát biểu switch:


using System;
class Switch
{
public static void Main()
{

- 44 -
NGUYỄN TRẦN MINH KHUÊ

Console.Write("Enter your selection (1, 2, or 3): ");


string s = Console.ReadLine();
int n = Int32.Parse(s);

switch(n)
{
case 1:
Console.WriteLine("value is {0}", 1);
break;
case 2:
Console.WriteLine("value is {0}", 2);
break;
case 3:
Console.WriteLine("value is {0}", 3);
break;
default:
Console.WriteLine("Sorry, invalid selection.");
break;
}
}
}

25.2. Phát biểu continue


Phát biểu continue chuyển điều khiển đến lần lặp kế tiếp trong phát biểu
vòng lặp với khai báo như sau:

continue;

Ví dụ khai báo phát biểu continue trong vòng lặp for:


using System;
class ContinueTest
{
public static void Main()
{
for (int i = 1; i <= 10; i++)
{
if (i < 9)
continue;
Console.WriteLine(i);
}
}
}

Trong ví dụ trên, biến i duyệt từ 1 đến 10, nếu biến i có giá trị còn nhỏ
hơn 9 thì những phát biểu khai báo giữa phát biểu continue và phát biểu kết thúc
của vòng for sẽ được bỏ qua.
25.3. Phát biểu default
Phát biểu default được khai báo trong phát biểu switch khi biểu thức so
sánh không thuộc một trong những giá trị khai báo trong phát biểu case.
Ví dụ chúng ta có khai báo default trong phát biểu switch như sau:

using System;
class SwitchTest
{
public static void Main()
{

- 45 -
NGUYỄN TRẦN MINH KHUÊ

Console.WriteLine("Sizes: 1=Small 2=Medium 3=Large");


Console.Write("Enter your selection: ");
string s = Console.ReadLine();
int n = int.Parse(s);
int cost = 0;
switch(n)
{
case 1:
cost += 25;
break;
case 2:
cost += 25;
goto case 1;
case 3:
cost += 50;
goto case 1;
default:
Console.WriteLine("Invalid selection);
break;
}
if (cost != 0)
Console.WriteLine("Insert {0} cents.", cost);
Console.WriteLine("Thank you.");
}
}

25.4. Phát biểu goto


Phát biểu gogo chuyển điều khiển đến một phát biểu nhãn với cú pháp:

goto identifier;
goto case constant-expression;
goto default;

Trong đó:
 identifier: là nhãn (label).
 constant-expression: là nhãn của phát biểu switch.
Ví dụ sử dụng phát biểu goto như sau:

using System;
public class GotoLabel
{
public static void Main()
{
int x = 200, y = 4;
int count = 0;
string[,] myArray = new string[x,y];
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
myArray[i,j] = (++count).ToString();
Console.Write("Enter the number to search for: ");
string myNumber = Console.ReadLine();
for (int i = 0; i < x; i++)
for (int j = 0; j < y; j++)
if (myArray[i,j].Equals(myNumber))
goto Found;

Console.WriteLine("The number {0} was not found.", myNumber);


goto Finish;
Found:
Console.WriteLine("The number {0} is found.", myNumber);

- 46 -
NGUYỄN TRẦN MINH KHUÊ

Finish:
Console.WriteLine("End of search.");
}
}

25.5. Phát biểu return


Phát biểu return dùng để kết thúc một phương thức và trả điều khiển về
cho phương thức gọi nó. Nếu phương thức là void thì phát biểu return sẽ được bỏ
qua.

return [expression];

Ví dụ, khai báo phát biểu return như sau:


using System;
class ReturnTest
{
static double CalculateArea(int r)
{
double area;
area = r*r*Math.PI;
return area;
}

public static void Main()


{
int radius = 5;
Console.WriteLine("The area is {0:0.00}", CalculateArea(radius));
}
}

26. PHÁT BIỂU CHECKED VÀ UNCHECKED


Phát biểu của C# khi thực thi có thể được kiểm tra ngữ cảnh hay không.
Nếu có kiểm tra thì ngoại lệ được phun ra khi số bị tràn bộ nhớ. Trong trường
hợp không kiểm tra thì kết quả số sẽ được bỏ qua hoặc sẽ bị cắt bỏ.
26.1. Phát biểu checked
Từ khoá checked dùng để điều khiể việc kiểm soát tràn bộ nhớ khi sử
dụng toán tử hay chuyển đổi dữ liệu kiểu số nguyên.
check được xem như phát biểu với cú pháp như sau:

checked block

check được xem như toán tử với cú pháp như sau:


checked (expression)

Trong đó
 block: Khối phát biểu chứa đựng các biểu thức cần kiểm tra.
 expression: Biếu thức được kiểm tra được đặt trong cặp dấu ().
Ví dụ sử dụng check như toán tử:

- 47 -
NGUYỄN TRẦN MINH KHUÊ

using System;

class OverFlowTest
{
static short x = 32767;
// Giá trị lớn nhất của short
static short y = 32767;

// Kiểm tra biểu thức


public static int myMethodCh()
{
int z = 0;

try
{
z = checked((short)(x + y));
}
catch (System.OverflowException e)
{
System.Console.WriteLine(e.ToString());
}
return z;
// Lỗi sẽ phu ra OverflowException
}

public static void Main()


{
Console.WriteLine("Checked output value
is: {0}", myMethodCh());
}
}

Sử dụng check như phát biểu


using System;

class TestClass
{
const int x = 2147483647;
const int y = 2;

public int MethodCh()


{
// phát biểu Checked
checked
{
int z = (x * y);
return z;
// Khi biên dịch sẽ bị lỗi
}
}

public static void Main()


{
TestClass myObject = new TestClass();
Console.WriteLine("Checked value: {0}", myObject.MethodCh());
}
}

26.2. Phát biểu unchecked


Tương tự như check, từ khoá unchecked dùng để điều khiển việc kiểm
soát tràn bộ nhớ khi sử dụng toán tử hay chuyển đổi dữ liệu kiểu số nguyên.
uncheck được xem như phát biểu với cú pháp như sau:

- 48 -
NGUYỄN TRẦN MINH KHUÊ

unchecked block

uncheck được xem như toán tử với cú pháp như sau:


unchecked (expression)

Trong đó
 block: Khối phát biểu chứa đựng các biểu thức không cần kiểm tra.
 expression: Biếu thức không kiểm tra được đặt trong cặp dấu ( ).
Ví dụ sử dụng uncheck như phát biểu

using System;

class TestClass
{
const int x = 2147483647;
const int y = 2;

public int MethodUnCh()


{
// phát biểu Unchecked
unchecked
{
int z = x * y;
return z;
// giá trị trả về -2
}
}

public static void Main()


{
TestClass myObject = new TestClass();
Console.WriteLine("Unchecked output value: {0}",
myObject.MethodUnCh());
}
}

Sử dụng uncheck như toán tử


using System;

class OverFlowTest
{
static short x = 32767;
static short y = 32767;

public static int myMethodUnch()


{
int z = unchecked((short)(x + y));
return z;
// Trả về giá trị là -2
}

public static void Main()


{
Console.WriteLine("Unchecked value is:
{0}", myMethodUnch());
}
}

- 49 -
NGUYỄN TRẦN MINH KHUÊ

27. PHÁT BIỂU LOCK


Từ khoá lock đánh dấu một khối phát biểu như giới hạn một phần không
cho phép thực hiện hành động trên đối tượng trong một khoảng thời gan sau đó
phục hồi lại trạng thái cho phép với cú pháp như sau:

lock(expression) statement_block

Trong đó
 expression: Chỉ định đối tượng mà bạn muốn khoá, expression phải là
kiểu reference.
 statement_block: Các phát biểu cần khoá.
Ví dụ:

using System;
using System.Threading;

class Account
{
int balance;

Random r = new Random();

public Account(int initial)


{
balance = initial;
}

int Withdraw(int amount)


{

// Điều kiện không bao giờ có giá trị true trừ


// khi khai báo lock được khai báo
if (balance < 0)
{
throw new Exception("Negative Balance");
}

// Khi báo phát biểu lock :


lock (this)
{
if (balance >= amount)
{
Console.WriteLine("Balance before
Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw
: -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after
Withdrawal : " + balance);
return amount;
}
else
{
return 0;
// tác vụ bị từ chối
}
}
}

- 50 -
NGUYỄN TRẦN MINH KHUÊ

public void DoTransactions()


{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}

class Test
{
public static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account (1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new
ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
}
}

28. PHÁT BIỂU FIXED


Ngăn ngừa việc bố trí lại biến bởi cơ chế garbage collector và chỉ sử dụng
với unsafe (điều này có nghĩa là biên dịch với tham số /unsafe) với cú pháp như
sau:

fixed ( type* ptr = expr ) statement

Trong đó
 type: Kiểu không quản lý hay void.
 ptr: Tên con trỏ.
 rxpr: Biểu thức ct đổi sang kiểu con trỏ.
 statement: Phát biểu hay một khối phát biểu.
Ví dụ
using System;

class Point {
public int x, y;
}

class FixedTest
{
// phương thức unsafe dùng đến pointer với int
unsafe static void SquarePtrParam (int* p)
{
*p *= *p;
}

unsafe public static void Main()


{

- 51 -
NGUYỄN TRẦN MINH KHUÊ

Point pt = new Point();


pt.x = 5;
pt.y = 6;
fixed (int* p = &pt.x)
{
SquarePtrParam (p);
}
Console.WriteLine ("{0} {1}", pt.x, pt.y);
}
}

29. KẾT LUẬN


Trong chương này, chúng ta tìm hiểu các phát biểu trong ngôn ngữ lập
trình C#.

- 52 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 6
PHƯƠNG THỨC

- 53 -
NGUYỄN TRẦN MINH KHUÊ

C# cung cấp nhiều loại phát biểu như: chọn, lặp, nhảy, kiểm tra, kiểm soát
ngoại lệ, lock và fixed. Trong mỗi phát biểu thường có một hay nhiều khai báo.
Bằng cách sử dụng toán tử và toán hạng chúng ta xây dựng một biểu thức so
sánh kết hợp với phát biểu chọn hay biểu thức gán sử dụng cho phát biểu lặp.
Các vấn đề chính sẽ được đề cập:
 Phương thức Main
 Phương thức void và phương thức trả về
 Tầm vực của phương thức
 Tham số

30. PHƯƠNG THỨC MAIN


Phương thức Main là phương thức được thực thi đầu tiên khi chương trình
thực thi với nhiều cách khai báo sau:

static void Main() {...}


static void Main(string[] args) {...}
static int Main() {...}
static int Main(string[] args) {...}

Phương thức Main có thể là void nhưng cũng có thể là một phương thức
trả về có hoặc không các tham số. Tham số có thể được truyền vào có dạng mảng
mỗi phần tử là một từ khi chương trình được thực thi.
Nếu trong chương trình có sử dụng đến mảng này thì người sử dụng cần
cung cấp giá trị dạng chuỗi, mỗi từ là giá trị của mỗi phần tử.

using System;
class voidmain
{
static void Main(string[] args)
{
foreach(string s in args)
{
Console.WriteLine(s);
}
Console.ReadLine();
}

Sau khi biên dịch class trên, để chạy tập tin exe bạn cung cấp tham số cho
phương thức Main như sau:

D:\CSharp\csc voidmain.cs
D:\CSharp\voidmain “Hello World”

Nếu thực thi chương trình trong Visual Studio.Net, bạn khai báo tham số
này trong phần ProjectName Properties | Debugging | Command line Arguments
như hình 6-1.

- 54 -
NGUYỄN TRẦN MINH KHUÊ

Hình 6-1: Khai báo tham số


Lưu ý:
 Nếu không sử dụng đến giá trị truyền vào khi thực thi tập tin, bạn
không cần khai báo tham số trong Main.
 Tham số truyền vào phương thức Main thường dùng cho chương trình
dạng Console.
31. PHƯƠNG THỨC VOID VÀ PHƯƠNG THỨC TRẢ VỀ
Phương thức được định nghĩa như một chương trình con có thể có giá trị
trả về.
31.1. Phương thức void
Một phương thức void được khai báo với từ khoá void sau từ khoá chỉ
định tầm vực của phương thức.

using System;
class Class1
{
static void Main(string[] args)
{
Console.WriteLine("void method");
tong();
Console.WriteLine();
}
/*Khai báo phương thức void*/
static void tong()
{

Console.Write("Enter the 1st number: ");


int ptu1=Convert.ToInt16(
Console.ReadLine());
Console.Write("Enter the 2rd number: ");
int ptu2=Convert.ToInt16(

- 55 -
NGUYỄN TRẦN MINH KHUÊ

Console.ReadLine());
Console.Write("Result: ");
Console.WriteLine(ptu1+ptu2);
}
}

31.2. Phương thức trả về


Khác với phương thức void, phương thức trả về được chỉ định kiểu dữ liệu
trước tên của phương thức và sử dụng phương thức return để trả về giá trị cho
phương thức.

using System;
class Class1
{
static void Main(string[] args)
{
Console.Write("Enter the 1st number: ");
int ptu1=Convert.ToInt16(
Console.ReadLine());
Console.Write("Enter the 2rd number: ");
int ptu2=Convert.ToInt16(
Console.ReadLine());
Console.Write("Result: "+
tong(ptu1, ptu2));
Console.WriteLine();
}

static int tong(int ptu1, int ptu2)


{
return ptu1+ptu2;
}
}

Lưu ý:
 Không nên khai báo return trước các khai báo còn lại trong phương thức.
 Phát biểu return được bỏ qua nếu khai báo chúng trong phương thức void.
32. TẦM VỰC CỦA PHƯƠNG THỨC<<KHÔNG PHẢI BIẾN NHƯ
TRÊN>
Tương tự như biến, tầm vực của phương thức được chia làm 3 loại như:
public, protected và private.
32.1. Public class này <<có thể gọi p/t public trong class kia >>
Cho phép truy cập đến phương thức mọi nơi, ví dụ chúng ta có hai class
trong tập tin .cs, phương thức khai báo với tầm vực là public có thể gọi trong
class khác như sau:
using System;
class publicroutine
{
public static int y=10;
static void Main() {
routine my = new routine();
Console.WriteLine("Routine tong ");
Console.WriteLine(my.tong(y,y+1));
Console.ReadLine();
}
}
Class routine

- 56 -
NGUYỄN TRẦN MINH KHUÊ

{
public int tong(int i,int j)
{
return i+j;
}
}

32.2. Protected
Cho phép truy cập đến phương thức trong phạm vi class khai báo nó hoặc
từ các class có khai báo kế thừa từ class này, ví dụ chúng ta có hai class trong tập
tin .cs, phương thức khai báo với tầm vực là protected có thể gọi trong class khác
như sau:
using System;
class protectedroutine
{
public static int y=10;
static void Main() {
routine my = new routine();
Console.WriteLine("Routine tong ");
Console.WriteLine(my.result(y,y+1));
//Console.WriteLine(my.tong(y,y+1)); //
Console.ReadLine();
}
}
Class routine
{
public int result(int i,int j)
{
return tong(i,j+10);
}
protected int tong(int i,int j)
{
return i+j;
}
}

Trong ví dụ trên, không cho phép gọi phương thức tong trong class
protectedroutine mà chỉ cho phép gọi phương thức này trong class routine.
32.3. Private
Từ khoá private cho phép truy cập đến phương thức trong phạm vi class
khai báo nó, ví dụ chúng ta có hai class trong tập tin .cs, phương thức khai báo
với tầm vực là private có thể gọi trong class khác như sau:
using System;
class privatedroutine
{
public static int y=10;
static void Main() {
routine my = new routine();
Console.WriteLine("Routine tong ");
Console.WriteLine(my.result(y,y+1));
//Console.WriteLine(my.tong(y,y+1));
Console.ReadLine();
}
}
Class routine
{
public int result(int i,int j)
{
return tong(i,j+10);

- 57 -
NGUYỄN TRẦN MINH KHUÊ

}
private int tong(int i,int j)
{
return i+j;
}
}

Nếu bạn không khai báo một trong ba từ khoá trên cho phương thức thì
mặc định là private.
33. THAM SỐ
Mỗi phương thức trong C# có thể có tham số truyền vào, kiểu dữ liệu của
tham số là mọi kiểu dữ liệu hỗ trợ trong C#. Có hai loại tham số chính trong
phương thức của C#.
33.1. Tham trị
Nếu tham số khai báo trong phương thức không có từ khoá ref hay out thì
tham số sẽ có giá trị trước khi truyền vào phương thức và ra khỏi phương thức
không thay đổi cho dù bên trong phương thức giá trị có thể thay đổi.
Ví dụ, chúng ta khai báo phương thức có tên paravalue nhận 2 tham số,
tham số thứ nhất và thứ hai là hai số nguyên theo hình thức tham trị, giá trị sẽ
được thay đổi trong phương thức nhưng kết quả in ra trước và sau khi truyền vào
phương thức là giống sau:
using System;
class valueparameter
{
static void Main(string[] args)
{
Console.WriteLine("Pass parameter");
int i=10;int j=5;
Console.WriteLine("i={0}, j={1}: ",i,j); Console.WriteLine("Result:
");
valuepara(i,j);
Console.WriteLine("i={0}, j={1}: ",i,j);
Console.WriteLine();
}

static void valuepara(int i, int j)


{
i++;j++;
Console.WriteLine("changed i={0},
j={1} ",i,j);
}
}

Kết quả in ra:


Pass parameter
i=10, j=5
Result:
changed i=11, j=6
i=10, j=5

33.2. Tham biến


Nếu tham số khai báo trong phương thức có từ khoá ref hay out thì tham
số sẽ có giá trị trước khi truyền vào phương thức và ra khỏi phương thức có thể
thay đổi do bên trong phương thức giá trị có thể thay đổi.

- 58 -
NGUYỄN TRẦN MINH KHUÊ

Trong C# để sử dụng tham biến, bạn có thể sử dụng một trong hai từ khoá
ref hay out.
33.2.1. Tham số với từ khoá ref
Khi sử dụng tham biến với từ khoá ref thì tham số truyền vào phương thức
phải khai báo từ khoá ref. Tham số này phải khởi tạo trước khi truyền vào
phương thức, đó là sự khác biệt với tham biến với từ khoá out, giá trị không cần
khởi tạo trước.
Một thuộc tính không phải là biến sẽ không thể truyền vào phương thức
dưới dạng tham biến với từ khoá ref. Chẳng hạn, chúng ta khai báo phương thức
refpara nhận hai tham số, tham số thứ nhất là số nguyên dưới dạng ref và tham số
thứ hai là số nguyên dưới dạng tham trị như sau:

using System;
class refparameter
{
static void Main(string[] args)
{
Console.WriteLine("Pass parameter");
/*Khởi tạo giá trị cho i*/
int i=10;int j=5;
Console.WriteLine("i={0}, j={1}
",i,j);
Console.WriteLine("Result: ");
/*Truyền i với tham số ref*/
refpara(ref i,j);
Console.WriteLine("i={0}, j={1}
",i,j);
Console.WriteLine();
}

static void refpara(ref int i, int j)


{
i++;j++;
Console.WriteLine("changed i={0},
j={1} ",i,j);
}
}

Kết quả in ra i có thay đổi thành 11 còn j thì vẫn giá trị trước khi vào
phương thức:
Pass parameter
i=10, j=5
Result:
changed i=11, j=6
i=11, j=5

33.2.2. Tham số với từ khoá out


Khi sử dụng tham biến với từ khoá out thì tham số truyền vào phương
thức phải khai báo từ khoá out. Tham số này không cần khởi tạo trước khi truyền
vào phương thức.

- 59 -
NGUYỄN TRẦN MINH KHUÊ

Một biến truyền vàp phương thức với từ khoá out không cấn khởi tạo. Tuy
nhiên, tham số này phải được gán giá trị trong phương thức trước khi trả về.
Một thuộc tính không phải là biến sẽ không thể truyền vào phương thức
dưới dạng tham biến với từ khoá out.
Chẳng hạn, chúng ta khai báo phương thức para nhận hai tham số, tham số
thứ nhất là số nguyên dưới dạng out và tham số thứ hai là số nguyên dưới dạng
ref như sau:

using System;
class outparameter
{
static void Main(string[] args)
{
Console.WriteLine("Pass parameter");
int i=0;int j=10;
Console.WriteLine("i={0}, j={1}
",i,j);
Console.WriteLine("Result: ");
para(out i,ref j);
Console.WriteLine("i={0}, j={1}
",i,j);
Console.WriteLine();
}

static void para(out int i, ref int j)


{
i=10;j++;
Console.WriteLine("changed i={0},
j={1} ",i,j);
}
}

Kết quả in ra i có thay đổi thành 11 và j thì có giá trị thay đổi là 6:

Pass parameter
i=0, j=5
Result:
changed i=11, j=6
i=10, j=6

33.3. Tham số params


Từ khoá params cho phép bạn chỉ định tham số nhận đối số mà số lượng
đối số là biến, từ khoá này thường sử dụng tham số là mảng.
Ví dụ, chúng ta khai báo phương thức và truyền vào một mảng dữ liệu
dưới hình thức tên biến của mảng hoặc các phần tử của mảng cách nhau dấu
phẩy.

using System;
public class myparams
{

public static void UseParams(params int[] list)


{
for ( int i = 0 ; i < list.Length ; i++ )

- 60 -
NGUYỄN TRẦN MINH KHUÊ

Console.WriteLine(list[i]);
Console.WriteLine();
}

public static void UseParams2(params object[] list)


{
for ( int i = 0 ; i < list.Length ; i++ )
Console.WriteLine(list[i]);
Console.WriteLine();
}

public static void Main()


{
UseParams(1, 2, 3);
UseParams2(1, 'a', "test");

int[] myarray = new int[3] {10,11,12};


UseParams(myarray);
}
}

Kết quả trình bày như sau:

1
2
3

1
a
test

10
11
12

34. KẾT LUẬN


Trong bài này, chúng ta tập trung tìm hiểu cách khai báo phương thức
Main, void và phương thức trả về cùng với tham số truyền vào phương thức.

- 61 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 7
OOP TRONG C#

- 62 -
NGUYỄN TRẦN MINH KHUÊ

C# là ngôn ngữ lập trình hướng đối tượng, chúng ta có thể cài đặt OOP
trong C# với: Constructor, Destructor, Garbage Collector, Overloading,
Inheritance, Overriding, Polymorphism và Interfaces.
Các vấn đề chính sẽ được đề cập:
 Constructors
 Định nghĩa Overloading
 Cài đặt Inheritance và Sealed class
 Cài đặt Overriding
 Cài đặt Polymorphism
 Abstract base classes
 Khai báo Interfaces
 Định nghĩa Interface

35. CONSTRUCTORS
35.1. Khai báo Constructor

Constructor là một phương thức đặc biệt cùng tên với tên của class được
gọi bất kỳ lúc nào sau kh class được tạo ra. Thuờng sử dụng Constructore để khởi
tạo giá trị. Chẳng hạn, chúng ta có class tên là clsA thì tên của Constructor cũng
có tên clsA như khai báo sau:

using System;
class testcon
{
public int j;
public int i;
/*Constructor*/
public testcon()
{
i=10;j=15;
}
}
/*Class chính*/
class calltestcon
{
static void Main()
{
testcon a=new testcon();
Console.WriteLine("i={0},
j={1}",a.i,a.j);
Console.ReadLine();
}
}

35.2. Constructors và tham số

Như trình bày ở trên Constructor là phương thức đặc biệt, chính vì vậy nó
cũng có thể có tham số, bạn có thể thay đổi giá trị của thuộc tính trong

- 63 -
NGUYỄN TRẦN MINH KHUÊ

constructor, chẳng hạn khi khởi tạo class, bằng cách tuyền giá trị vào tham số
tương ứng của constructor như khai báo sau:

using System;
class constructorparameter
{
public int j=10;
public int i;
public constructorparameter()
{
i=10;
}
public constructorparameter(int d)
{
j+=d;
}

}
class calltestcon
{
static void Main()
{
Console.WriteLine("Constructor
without parameter");
constructorparameter cplus= new
constructorparameter();
Console.WriteLine("i={0},
j={1}",cplus.i,cplus.j);

Console.WriteLine("Constructor with
parameter");
constructorparameter csharp=new
constructorparameter(20);
Console.WriteLine("i={0},
j={1}",csharp.i,csharp.j);
Console.ReadLine();
}
}

35.3. Khai báo Destructors

Trong C# không có destructor, nhưng chúng cho phép khai báo cấu trúc
này tương tự như trong ngôn ngữ lập trình C++. Phương thức destructor sẽ được
gọi khi một đối tượng bị huỷ bỏ. Tuy nhiên, trong C# sử dụng khai niệm Garbage
collector thay vì sử dụng cấu trúc destructor.
Để khai báo destructor trong C#, bạn khai báo tên trùng với tên của class
nhưng có ký tự ~ đi trước.

using System;
class destructorparameter
{
public int j=10;
public int i;
public destructorparameter ()
{
i=10;j++;
}

~ destructorparameter (){

- 64 -
NGUYỄN TRẦN MINH KHUÊ

}
class calltestcon
{
static void Main()
{
destructorparameter cplus= new
destructorparameter ();
Console.WriteLine("i={0},
j={1}",cplus.i,cplus.j);
Console.ReadLine();
}
}

35.4. Garbage Collector

Garbage Collector có trách nhiệm giải phóng bộ nhớ bị chiếm bởi các đối
tượng không còng sử dụng hay tham chiếu.
Khi một đối tượng bị huỷ, trình thực thi sẽ liệt kê đối tượng này vào danh
sách yêu cầu bị huỷ. Garbage Collector kiểm tra xem đối tượng này còn sử dụng
nữa hay không, nếu tên của đối tượng này không xuất hiện trong danh sách cần
xoá thì chúng sẽ được đánh dấu sẵng sàng. Sau khi đã đánh dấu tất các đối tượng
cần xoá, chúng sẽ thực hiện tiếp tác vụ sẽ xoá tất cả các đối tượng đói khỏi danh
sách này và tiếp tục thực hiện cho lần kế tiếp.
36. ĐỊNH NGHĨA OVERLOADING

Những phương thức khai báo trong C# có thể cùng tên (overload) theo hai
cách sau:
 Khác số lượng tham số truyền vào phương thức
 Chỉ định kiểu dữ liệu của tham số khác nhau
Overload không hỗ trợ phương thức trả về giá trị trong ngôn ngữ lập trình
C#. Bạn có thể xem constructor như một phương thức overload.
36.1. Overloading khác số lượng tham số

C# cho phép khai báo phương thức cùng tên trong class với số lượng tham
số khác nhau:

using System;
class overload
{
public static int op1=0;
public static int op2=0;
public static int total=0;
/* phương thức “tinh” có 2 tham số */
public static void tinh(int a, int b)
{
total=a+b;

- 65 -
NGUYỄN TRẦN MINH KHUÊ

}
/* phương thức “tinh” có 3 tham số */
public static void tinh(int a, int b,string symbol)
{
switch(symbol)
{
case "+":
total=a+b;break;
case "-":
total=a-b;break;
case "*":
total=a*b;break;
case "/":
total=a/b;break;
case "%":
total=a%b;break;
}

static void Main()


{
Console.WriteLine();

Console.WriteLine("Nhap hai so a va b");


Console.WriteLine("----------------");
Console.Write("Op1= ");
op1=Convert.ToInt16(Console.ReadLine());
Console.Write("Op2= ");
op2=Convert.ToInt16(Console.ReadLine());
/*Gọi phương thức “tinh” với 3 tham số */
tinh(op1,op2,"-");
Console.WriteLine("Hieu: "
+total.ToString());
/*Gọi phương thức “tinh” với 2 tham số */
tinh(op1,op2);
Console.WriteLine("Tong: " +
total.ToString());

}
}

36.2. Overloading khác kiểu tham số

Trong trường hợp tham số truyền vào phương thức cùng nhau thì phải
khác nhau về kiểu dữ liệu, ví dụ chúng ta khai báo:

using System;
class overload
{
public static int op1=100;
public static long op2=15000000000;
public static long total=0;
/*Khai báo phương thức “tinh” cùng tên*/
public static void tinh(int a, int b)
{
total=a+b+100;
}
/*Khai báo phương thức “tinh” cùng tên và khác kiểu dữ liệu của tham số*/
public static void tinh(int a, long b)
{
total=a+b;

- 66 -
NGUYỄN TRẦN MINH KHUÊ

static void Main()


{
Console.WriteLine();
Console.WriteLine("Nhap hai so a va b");
Console.WriteLine("-----------------");
Console.WriteLine("Op1= "+op1);
Console.WriteLine("Op2= "+op2);
/*Lần đầu tiên gọi thì sẽ gọi phương thức
đầu tiên do Op2 có giá trị là long*/
tinh(op1,op2);
Console.WriteLine("Tong: "
+total.ToString());
/*Lần thứ hai gọi thì sẽ gọi phương thức
thứ hai do Op2 có giá trị là int*/
op2=150;
tinh(op1,op2);
Console.WriteLine("Tong: "
+total.ToString());
}
}

37. CÀI ĐẶT INHERITANCE

Ngôn ngữ lập trình hướng đối tượng cho phép chúng ta khai báo và sử
dụng lại class nhằm sử dụng lại những tài nguyên đã có. Khái niệm sử dụng lại
class đã khai báo trước đó được biến đến là tính kế thừa (Inheritance).
37.1. Kế thừa

C# hỗ trợ đa kế thừa cho phép một class có thể kế thừa từ nhiều class
khác.

using System;
/*Khai báo class để cho phép class khác kế thừa*/
class Tinhtoan
{
public long Tinh(int a, int b,string symbol)
{
long total=0;
switch(symbol)
{
case "+":
total=a+b;break;
case "-":
total=a-b;break;
case "*":
total=a*b;break;
case "/":
total=a/b;break;
case "%":
total=a%b;break;
}
return total;
}
}
/*Khai báo class để kế thừa class khác*/
class inheritance:Tinhtoan
{
static void Main()
{
inheritance t =new inheritance();

- 67 -
NGUYỄN TRẦN MINH KHUÊ

Console.WriteLine("Nhap so luong ban");


Console.WriteLine("------------------");
Console.Write("So luong= ");
int a=Convert.ToInt16(Console.ReadLine());
Console.Write("Don gia= ");
int b=Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Ket qua ke thua");
Console.WriteLine("------------------");
long kq=t.Tinh(a,b,"*");
Console.WriteLine("Ket qua: " +
kq.ToString());
Console.ReadLine();
}
}

37.2. Nghiêm cấm kế thừa

Trong trường hợp khai báo class không cho phép class khác kê thừa bạn
sử dụng từ khoá sealed.

using System;
/*Khai báo class không cho phép kế thừa*/
sealed class Tinhtoan
{
public long Tinh(int a, int b,string symbol)
{
long total=0;
switch(symbol)
{
case "+":
total=a+b;break;
case "-":
total=a-b;break;
case "*":
total=a*b;break;
case "/":
total=a/b;break;
case "%":
total=a%b;break;
}
return total;
}
}
/*nếu khai báo kế thừa sẽ phát sinh lôi khi biên dịch*/
class clssealed//:Tinhtoan
{
static void Main()
{
Tinhtoan t =new Tinhtoan();
//clssealed t =new clssealed();
/*Khong the ke thua, cho nên khai báo để khởi
tạo đối tượng Tinhtoan thay vì clssealed*/
Console.WriteLine("Nhap so luong ban ");
Console.WriteLine("------------------");
Console.Write("So luong= ");
int a=Convert.ToInt16(Console.ReadLine());
Console.Write("Don gia= ");
int b=Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Khong the ke thua");
Console.WriteLine("------------------");
long kq=t.Tinh(a,b,"*");
Console.WriteLine("Ket qua: " +
kq.ToString());
Console.ReadLine();

- 68 -
NGUYỄN TRẦN MINH KHUÊ

}
}

38. CÀI ĐẶT OVERRIDING

Chúng ta vừa tham khảo cách cài đặt inheritance trong C#, trong trường
hợp có hai phương thức khác báo trong hai class có kế thừa nhau cùng tên thì
phải sử dụng từ khoá new để cho phép overriding.

using System;
/*Khai báo phương thức cho phép kế thừa*/
class overriding
{
public long tinh(int a, int b,string symbol)
{
long total =0;
switch(symbol)
{
case "+":
total=a+b;break;
case "-":
total=a-b;break;
case "*":
total=a*b;break;
case "/":
total=a/b;break;
case "%":
total=a%b;break;
}
return total;
}
}

class testoverriding:overriding
{
new long tinh(int a, int b,string symbol)
{
/*cong them 10 de biet su khac biet
voi phuong thuc tren*/
return a+b+10;
}

static void Main()


{
testoverriding t =new testoverriding();
Console.WriteLine();

Console.WriteLine("Nhap hai so a va b");


Console.WriteLine("----------------");
Console.Write("Op1= ");
int op1=
Convert.ToInt16(Console.ReadLine());
Console.Write("Op2= ");
int op2=
Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Tong hai so a va b: "+
t.tinh(op1,op2,"+"));
Console.ReadLine();

}
}

- 69 -
NGUYỄN TRẦN MINH KHUÊ

Sau khi khai báo kề thừa class overriding, thay vì sử dụng phương thức
Tinh của class này bạn có thể khai báo phương thức cùng tên sau đó sử dụng từ
khoá để overriding phương thức Tinh trong class kế thừa.
39. CÀI ĐẶT POLYMORPHISM

Polymorphism bao gồm phương thức ảo (Virtual Method) cho phép chúng
ta cài đặt phương thức xuất phát từ lớp khác trong quá trình thực thi.
Khi khai báo các class khác có kế thừa từ class có khai báo Virtual
Method phải sử dụng từ khoá override, khi đó đối tượng khởi tạo sẽ trở thành
một mảng bao gồm các class thành viên như sau:

using System;
public class Salary
{
public virtual int Income(int SalaryContract,
int Allowance,int Rate)
{ return (SalaryContract + Allowance)*Rate;
}
}
public class Commission:Salary
{
public override int Income(int USD,int VND,
int Rate)
{
return USD*Rate + VND;
}
}
public class OverTime:Salary
{
public override int Income(int USD,int VND,
int Rate)
{
return USD*Rate + VND;
}
}
public class GrossIncome
{
static int Rate=15000;
/*Exchange Rate base on USD*/
static void Main()
{
Salary[] inc=new Salary[3];
inc[0]=new Salary();
inc[1]=new Commission();
inc[2]=new OverTime();
int sal =inc[0].Income(100,50,Rate);
int com =inc[1].Income(0,100000,Rate);
int ot=inc[2].Income(0,100000,Rate);
Console.WriteLine();

Console.WriteLine("Tien luong");
Console.WriteLine("-------------------");
Console.Write("Quy ra tien dong:");
Console.WriteLine(sal+com+ot);
Console.WriteLine("-------------------"); Console.WriteLine("Salary:{0}\n
Commissoin:{1}\nOT:{2}",sal,com,ot);
Console.Write("Press any key to continue");
Console.ReadLine();
}

- 70 -
NGUYỄN TRẦN MINH KHUÊ

40. ABSTRACT BASE CLASSES

C# cho phép bạn cài đặt một lớp trừ tượng cơ sở với từ khoá Abstract, các
phương thức khai báo trong lớp này có thể có phần khai báo bên trong hoặc
không.
Trong trường hợp những phương thức không có phần thân chương trình
thì bạn có thể khai báo chúng trong một class khác sau đó khai báo kế thừa từ
class này.

using System;
abstract class Tinhtoan
{
public abstract long Tinh(int a, int b);
}

class Thuvien: Tinhtoan


{
public override long Tinh(int a, int b)
{
return (a+b);
}
}

class TestAbstract
{
static void Main(string[] args)
{
Thuvien tv= new Thuvien();
Tinhtoan tt=tv;
int i=1000; int j=2000;
/*Gọi phương thức Tinh trên class
Tinhtoan*/
Console.WriteLine("Ket qua: " +
tt.Tinh(i,j));
Console.ReadLine();
}
}

41. KHAI BÁO INTERFACE

Chúng ta vừa tham khảo cách cài đặt một class dạng lớp trừu tượng,
interface là một class trừu tượng nó chứa đựng các phương thức trừu tượng và
không trừu tượng.
41.1. Định nghĩa Interface

Đối tượng của interface không bao giờ được tạo ra, cho phép bạn khai báo
tên phương thức trong class này nhưng phần thân của phương thức sẽ được khai
báo trong class khác.
Chẳng hạn, bạn khai báo tên phương thức trong class clsA như sau:

- 71 -
NGUYỄN TRẦN MINH KHUÊ

using System;
public interface Tinhtoan
{
long Tinh(int a, int b);
}
/*Khai báo phần thân của phương thức*/
public class Tinhtoans: Tinhtoan
{
public long Tinh(int a, int b)
{
a++;b++;
return (a+b);
}
}

class TestInterface
{
static void Main(string[] args)
{
Tinhtoans tt= new Tinhtoans();
int i=1000; int j=2000;
Console.WriteLine("Ket qua: " +
tt.Tinh(i,j));
Console.ReadLine();
}
}

41.2. Multi Interface

Trong C# cho phép chúng ta cài đặt đa interface, bằng cách này bạn có thể
khai báo tên của phương thức trên hai interface khác nhau nhưng phần thân của
chúng được khai báo trong cùng một class.

using System;
/*Khai báo interface thứ nhất*/
public interface Tinhtoan
{
long Tinh(int a, int b);
}
/*Khai báo interface thứ hai*/
public interface Inan
{
void Ketqua(int a, int b);
}
/*Khai báo phần thân của các phương thức trong
interface thứ nhất và thứ hai*/
public class Tinhtoans: Tinhtoan,Inan
{
public long Tinh(int a, int b)
{
a++;b++;
return (a+b);
}
public void Ketqua(int a, int b)
{
Console.WriteLine("a=" +a);
Console.WriteLine("a=" +b);
}
}

class TestInterface
{
static void Main(string[] args)
{

- 72 -
NGUYỄN TRẦN MINH KHUÊ

Tinhtoans tt= new Tinhtoans();


int i=1000; int j=2000;
tt.Ketqua(i,j);
Console.WriteLine("Ket qua: " +
tt.Tinh(i,j));
Console.ReadLine();
}
}

41.3. Explicit Interface

Trong trường hợp hai phương thức khai báo trong hai interface cùng tên
nhau, bạn khai báo phần thân của mỗi phương thức trong class kế thừa bằng cách
chỉ định tên của interface cho mỗi phương thức.

using System;
/*Khai báo phương thức “tinh” trong interface
thứ nhất*/
public interface Tinhtoan
{
long Tinh(int a, int b);
}
/*Khai báo phương thức “tinh” trong interface
thứ hai*/
public interface Calculate
{
long Tinh(int a, int b);
}
/*Cai đặt 2 phương thức “tinh” trong class
thứ nhất*/
public class Tinhtoans: Tinhtoan, Calculate
{
long Tinhtoan.Tinh(int a, int b)
{
a++;b++;
return (a+b);
}
long Calculate.Tinh(int a, int b)
{
return (a+b);
}
}

class TestInterface
{
static void Main(string[] args)
{
Tinhtoans tt= new Tinhtoans();
int i=1000; int j=2000;
Console.WriteLine("Ket qua: " +
tt.Tinh(i,j));
Console.ReadLine();
}
}

42. KẾT LUẬN

Trong chương này, chúng ta tìm hiểu cài đặt OOP trong C# với
Constructor, Destructor, Garbage Collector, Overloading, Inheritance,
Overriding, Polymorphism và Interfaces.

- 73 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 8
KIỂM SOÁT NGOẠI LỆ

- 74 -
NGUYỄN TRẦN MINH KHUÊ

C# cung cấp cấu trúc điều khiển try-cacth-finally cho phép chúng ta kiểm
soát lỗi trong quá trình thực thi chương trình. Đối tượng Exception cung cấp
toàn bộ thông tin của lỗi xảy ra.
Các vấn đề chính sẽ được đề cập:
 Tìm hiểu lớp kiểm soát lỗi (Exceptions Class)
 Khai báo kiểm soát lỗi (Exceptions Handle)
 Lỗi do người sử dụng định nghĩa

43. TÌM HIỂU LỚP KIỂM SOÁT LỖI

Mọi lớp Exception khác như IOException, SystemException,


OutOfMemoryException, OverflowException, đều xuất thân từ lớp Exception.

Exception

IOException

SystemException

OutOfMemoryException

OverflowException

FormatException

….....

Tuỳ thuộc vào việc xác định lỗi phát sinh trong khi thực thi chương trình
thuộc loại nào thì bạn sẽ sử dụng đối tượng đó cho phù hợp.
Khi sử dụng đúng đối tượng Exception cho lỗi phát sinh, đối tượng sẽ
cung cấp thông tin chi tiết của lỗi xảy ra thay vì sử dụng trường hợp tổng quát.
Tuy nhiên, trong trường hợp không xác định được lỗi sẽ phát sinh thuộc
loại đối tượng chỉ định, bạn sử dụng đối tượng Exception để nắm các thông tin
chính do lỗi phun ra.

- 75 -
NGUYỄN TRẦN MINH KHUÊ

44. KHAI BÁO KIỂM SOÁT LỖI


C# hỗ trợ cấu trúc kiểm soát ngoại lệ xảy ra trong đoạn chương trình là
try, throw, catch và finally với tổ hợp khai báo như (throw, try-catch, try-finally,
try-catch-finally).
44.1. Phát biểu throw
Phát biểu throw dùng để phát ra tín hiệu của sự cố bất thường trong khi
chương trình thực thi với cú pháp:

throw [expression];

Trong đó
 expression là đối tượng nó sẽ được bỏ qua khi noại lệ hiện hành nằm
trong mệnh đề catch.
Ví dụ:

using System;
public class ThrowTest
{
public static void Main()
{
string s = null;

if (s == null)
{
throw(new ArgumentNullException());
}

Console.Write("The string s is null");


// not executed
}
}
44.2. Phát biểu try catch
Phát biểu try-catch bao gồm nhiều mệnh đề catch trong try cho phép kiểm
soát nhiều loại ngoại lệ xảy ra của đoạn chương trình khai báo trong try như sau:

try try-block
catch (exception-declaration-1) catch-block-1
catch (exception-declaration-2) catch-block-2
...
try try-block catch catch-block

Thông thường khai báo mệnh đề try ứng với một mệnh đề catch như sau:

using System;
class trycatch
{
public static void Main()
{
trycatch x = new trycatch ();
try
{
string s = null;

- 76 -
NGUYỄN TRẦN MINH KHUÊ

x.MyFn(s);
}

catch (Exception e)
{
Console.WriteLine("{0}
Exception caught.", e);
}
}

public void MyFn(string s)


{
if (s == null)
throw(new ArgumentNullException());
}
}

Nếu đoạn chương trình trong khai báo try có thể có nhiều loại exception
xảy ra, chúng ta có thể sử dụng nhiều mệnh đề catch như sau:

using System;
class MyClass
{
public static void Main()
{
MyClass x = new MyClass();
try
{
string s = null;
x.MyFn(s);
}

// Chỉ định ngoại lệ kiểm soát


catch (ArgumentNullException e)
{
Console.WriteLine("{0}
First exception caught.", e);
}

// Nếu ngoại lệ không thuộc catch trên


catch (Exception e)
{
Console.WriteLine("{0} Second exception caught.", e);
}

public void MyFn(string s)


{
if (s == null)
throw new ArgumentNullException();
}
}

Lưu ý: Mệnh đề catch thứ hai sẽ được sử dụng khi chương trình có lỗi.
Tuy nhiên, chúng ta có thể thay đổi mệnh đề catch thứ hai bằng cách khai báo
như sau:

using System;
class MyClass
{
public static void Main()

- 77 -
NGUYỄN TRẦN MINH KHUÊ

{
MyClass x = new MyClass();
try
{
string s = null;
x.MyFn(s);
}
catch (ArgumentNullException e)
{
Console.WriteLine("{0}
First exception caught.", e);
}
}

public void MyFn(string s)


{
if (s == null)
throw new Exception();
}
}

44.3. Phát biểu try finally


Khối khai báo trong finally dùng để xoá những tài nguyên được tạo ra
trong try, điều khiển sẽ được chuyển đến khối finally khi chương trình thoát khỏi
khối try với cú pháp như sau:

try try-block finally finally-block

Trong đó
 try-block: Chứa đựng các khai báo muốn kiểm soát ngoại lệ.
 finally-block: Chứa đựng các khai báo để xoá tài nguyên sử dụng
trong try.
Ví dụ:

using System;
public class TestTryFinally
{
public static void Main()
{
int i = 123;
string s = "Some string";
object o = s;

try
{
/* Invalid conversion;
o contains a string not an int*/
i = (int) o;
}

finally
{
Console.Write("i = {0}", i);
}
}
}

- 78 -
NGUYỄN TRẦN MINH KHUÊ

44.4. Phát biểu try catch finally


Khối khai báo trong finally dùng để xoá những tài nguyên được tạo ra
trong try, điều khiển sẽ được chuyển đến khối finally khi chương trình thoát khỏi
khối try, trong khi khai báo trong catch dùng để kiểm soát exception xảy ra
trontg try như cú pháp sau:

try
try-block
catch
catch-block
finally
finally-block

Trong đó
 try-block: Chứa đựng các khai báo cần kiểm soát ngoại lệ.
 catch-block: Chứa đựng các khai báo kiểm soát ngoại lệ.
 finally-block: Chứa đựng các khai báo để xoá tài nguyên sử dụng
trong try.
Ví dụ:

using System;
public class trycatchfinally
{
public static void Main ()
{
try
{
Console.WriteLine("Executing the try statement.");
throw new NullReferenceException();
}

catch(NullReferenceException e)
{
Console.WriteLine("{0}
Caught exception #1.", e);
}

catch
{
Console.WriteLine("Caught
exception #2.");
}

finally
{
Console.WriteLine("Executing finally
block.");
}
}
}

45. LỖI DO NGƯỜI SỬ DỤNG ĐỊNH NGHĨA

Dựa vào lớp Exception, chúng ta có thể phun ra thông báo tuỳ thích mỗi
khi phát sinh lỗi. Chẳng hạn, bạn khai báo đoạn chương trình đọc tập tin trên đĩa,

- 79 -
NGUYỄN TRẦN MINH KHUÊ

nếu tập tin không tồn tại thay vì xuất câu thông báo thì bạn phun ra chuỗi như
thuộc tính Message của đối tượng Exception.

using System;
using System.IO;
class Class1
{
static void Main(string[] args)
{
try{
Class1 t = new Class1();
t.CustomException(args[0]);
}catch(Exception e)
{
Console.WriteLine("Error: " + e);
}

void CustomException( string fname)


{
try{
FileInfo fs =new FileInfo( fname);
if(fs.Exists==true)
{
Console.WriteLine("FullName: " +
fs.FullName);
Console.WriteLine("LastWriteTime: "
+ fs.LastWriteTime);
Console.WriteLine("LastAccessTime:"
+ fs.LastAccessTime);
Console.WriteLine("Size: " +
fs.Length.ToString());
Console.ReadLine();
}
else
{
throw new
Exception("Khong tim thay tap tin");
}
}catch(IOException e)
{
Console.WriteLine("Error: " + e);
}

}
}

46. KẾT LUẬN

Trong bài này, chúng ta tìm hiểu các đối tượng Exception và các khai báo
dùng để kiểm soát lỗi phát sinh trong khi thực thi chương trình.

- 80 -
NGUYỄN TRẦN MINH KHUÊ

CHƯƠNG 9
KHÔNG GIAN TÊN
VÀ THUỘC TÍNH

- 81 -
NGUYỄN TRẦN MINH KHUÊ

Trong những chương trước chúng ta tìm hiểu cách khai báo không gian tên
của .NET, bằng cách khai báo không gian tên sau đó sử dụng chung cho ứng
dụng.
Ngoài ra, bài học này cung cấp cho bạn cách khai báo và truy cập thuộc tính
trong class.
Các vấn đề chính sẽ được đề cập:
 Không gian tên
 Khai báo và sử dụng thuộc tính

47. KHÔNG GIAN TÊN

Khi làm việc với một dự án lớn, có rất nhiều class được tạo ra từ nhiều
nhóm lập trình, đôi khi các class này không kết hợp thành một nhóm, để kết hợp
các class này lại với nhau bạn sử dụng không gian tên (namespace).
Namespace cho phép chúng ta tổ chức mã nguồn và bảo dảm rằng chúng
sẽ không dư thừa và đơn giản khi sử dụng lại trong một ứng dụng khác.
47.1. Khai báo namespace

Để khai báo namespace trong C#, bạn sử dụng cú pháp như sau:

namespace namespacename
{
/*Khai báo*/
}

Lưu ý rằng, namespace mặc định là public, chính vì vậy không cho phép
khai báo từ khoá public, protected hay private trước từ khoá namespace.
Chẳng hạn, có một số class như sau khai báo trên một hay nhiều tập tin
class:

/*Hai class trong tập tin clsAdvanced.cs*/


public class myDatabase
{

}
public class myCom
{

/*Hai class trong tập tin clsSimple.cs*/


public class myCommmon
{

}
public class myUtility
{

- 82 -
NGUYỄN TRẦN MINH KHUÊ

Sử dụng namespace để kết hợp các class trên lại với nhau bằng cách khai
báo như sau:

namespace mynamespace
{
public class myDatabase
{

}
public class myCom
{

}
public class myCommmon
{

}
public class myUtility
{

}
}

47.2. Namespace lồng

Namespace có thể khai báo lồng, điều này có nghĩa là khai báo một
Namespace trong một Namespace. Giả sử rằng, chúng ta muốn có hai
Namespace con trong mynamespace là mySQL và myAccess thì khai báo như
sau:

namespace mynamespace
{
namespace mySQL
{
public class mySQLDatabase
{

}
public class mySQLCom
{

}
public class mySQLCommmon
{

}
public class mySQLUtility
{

}
}
namespace myAccess
{
public class myAccessDatabase
{

- 83 -
NGUYỄN TRẦN MINH KHUÊ

public class myAccessCom


{

}
public class myAccessCommmon
{

}
public class myAccessUtility
{

}
}
}

Tuy nhiên, bằng cách khai báo như sau bạn cũng có thể tạo ra một
namespace lồng trong namespace khác:

namespace mynamespce.mySQL
{
public class mySQLDatabase
{

}
public class mySQLCom
{

}
public class mySQLCommmon
{

}
public class mySQLUtility
{

47.3. Truy cập namespace

Khi sử dụng class trong namespace đó thì bạn chỉ cần gọi đến tên class
muốn dùng, ví dụ sử dụng class có tên mySQLDatabase thì khai báo như sau:

namespace mynamespace
{
namespace mySQL
{
public class mySQLDatabase
{

}
...
public classMain
{
static void Main()
{
/*Khai báo class trong không gian
tên hiện hành*/
mySQLDatabase t = new
mySQLDatabase();
...
}

- 84 -
NGUYỄN TRẦN MINH KHUÊ

}
}
namespace myAccess
{
public class myAccessDatabase
{

}
...
}
}

Tuy nhiên, trong trường hợp sử dụng class của namespace khác trong
namespace hiện hành, bạn phải khai báo tên namespace đó như sau:

namespace mynamespace
{
namespace mySQL
{
public class mySQLDatabase
{

}
...
public classMain
{
static void Main()
{
/*Khai báo class của không gian tên
khác*/
myAccess.myAccessDatabase t = new
myAccess.myAccessDatabase();
...
}
}
}
namespace myAccess
{
public class myAccessDatabase
{

}
...
}
}

47.4. Sử dụng chỉ mục

Do tên của namespace qua dài hay sử dụng class của namespace tên khác
như sau:

mynamespace.myAccess.myAccessDatabase
t = new mynamespace.myAccess.myAccessDatabase();

Thay vì khai báo chỉ định tên namespace và tên class như trên, bạn có thể
sử dụng chỉ mục như sau:

using mynamespace.myAccess;
...

- 85 -
NGUYỄN TRẦN MINH KHUÊ

myAccessDatabase t = new myAccessDatabase();

Lưu ý rằng, chỉ mục namespace trong class phải được khai báo trên mọi
thành viên khác của class ví dụ:

using System;
using System.IO;
using mynamespace.myAccess;

namespace FirstCSharp
{
/// <summary>
/// Summary description for Class3.
/// </summary>
public class Class3
{
static void Main()
{
myAccessDatabase t = new
myAccessDatabase();
...
}
}
}

47.5. Bí danh của namespace

Ngoài cách sử dụng khai báo chỉ mục như trên, bạn có thể sử dụng bí danh
để khai báo namespace như sau:

using System;
using System.IO;
using ns=mynamespace.myAccess.
myAccessDatabase;

namespace FirstCSharp
{
/// <summary>
/// Summary description for Class3.
/// </summary>
public class Class3
{
static void Main()
{
ns t = new ns();
...
}
}
}

Trong trường hợp trong hai namespace có hai class trùng tên nhau, khi
khai báo để sử dụng phải chỉ định tên namespace của nó. Chẳng hạn, trong hai
namespace có tên mySQL và myAccess đều có class tên là Test, như vậy khi
khai báo bạn sử dụng cú pháp như sau:

using System;

- 86 -
NGUYỄN TRẦN MINH KHUÊ

using System.IO;
using mynamespace.mySQL;
using mynamespace.myAccess;

namespace FirstCSharp
{
/// <summary>
/// Summary description for Class3.
/// </summary>
public class Class3
{
static void Main()
{
Test t = new MyAccess.Test();
...
}
}
}

48. THUỘC TÍNH

Khái niệm thuộc tính đã có trong ngôn ngữ lập trình Visual Basic, trong
C# một trường được khai báo và cho phép đọc hay gán giá trị gọi là thuộc tính
(properties).

public class GetSetPro


{ int liA=0;
int liB=0;
}

Tương tự như trong ngôn ngữ lập trình C++, để khai báo thuộc tính trong
C# bạn dùng hai phương thức set và get như sau:

public class GetSetPro


{
int liA=0;
int liB=0;
public int getA
{
get
{
return liA;
}
set
{
liA = value;
}
}
}

C# cung cấp hai loại thuộc tính là thuộc tính chỉ đọc và thuộc tính đọc và
ghi.

- 87 -
NGUYỄN TRẦN MINH KHUÊ

48.1. Thuộc tính đọc và ghi

Một thuộc tính được xem là đọc và ghi là cho phép bạn gán (set) giá trị
vào thuộc tính hay lấy (get) giá trị ra từ thuộc tính. Để khai báo thuộc tính vừa
đọc và ghi bạn sử dụng cú pháp như sau:

public int getA


{
get
{
return liA;
}
set
{
liA = value;
}
}

48.2. Thuộc tính chỉ đọc

Nếu muốn thuộc tính chỉ đọc, bạn chỉ sử dụng phương thức get như khai
báo như sau:

public int getA


{
get
{
return liA;
}
}

48.3. Sử dụng thuộc tính

Sau khi khai báo thuộc tính, bạn có thể truy cập đến thuộc tính đế gán hay
lấy giá trị bằng cách khai báo như sau:

using System;
public class GetSetPro
{
int liA;
int liB=100;
public int getAndSet
{
get
{
return liA;
}

set
{
liA = value;
}
}
public int getOnly
{
get
{
return liB;

- 88 -
NGUYỄN TRẦN MINH KHUÊ

}
}
}
class UsePro
{
static void Main()
{
GetSetPro GS=new GetSetPro();
/*thuộc tính đọc và ghi */
GS.liA=1500;
Console.WriteLine(“liA={0}”,GS.liA);
/*thuộc tính chỉ đọc */
Console.WriteLine(“liA={0}”,GS.liB);
}
}

49. KẾT LUẬN

Trong bày này, chúng ta tìm hiểu cách cài đặt và sử dụng một không gian
tên trong chương trình.
Bằng cách khai báo thuộc tính với hai phương thức chính là get và set, bạn
cho phép gán giá trị từ bên ngoài vào biến hay lấy giá trị từ các trường này.

- 89 -
NGUYỄN TRẦN MINH KHUÊ

DIỄN GIẢI

- 90 -
NGUYỄN TRẦN MINH KHUÊ

Khi làm việc với ngôn ngữ lập trình C#, chúng ta cần quan tâm đến các ký
hiệu, ký tự đặc biệt và ghi chú trong chương trình.
Các vấn đề chính sẽ được đề cập:
 Cú pháp
 Ghi chú (Comment)
 Dấu hiệu (Token)
 Lỗi do người sử dụng định nghĩa

50. CÚ PHÁP

Tất cả các biểu thức điều kiện khai báo trong các phát biểu điều khiển
phải đóng bởi cặp dấu (), ví dụ như khai báo:

if(!(i==j))
{

Mọi câu lệnh phải được kết thúc bằng dấu ; chẳng hạn khai báo:

System.Console.WriteLine("C# Basic");

Bắt đầu class, phương thức, interface, namespace, ... đều bắt đầu dấu { và
kết thúc dấu }. Ngoài ra, trong phát biểu điều khiển có nhiều hơn một câu lệnh,
bạn cũng sử dụng cặp dấu trên.
51. GHI CHÚ

Để khai báo chi chú cho một câu diễn giải trong chương trình, bạn sử
dụng cặp dấu // trước đầu câu, ví dụ câu “Hello, world program” là chuỗi diễn
giải.

// Hello, world program

class Hello
{
static void Main() {
System.Console.WriteLine("C# Basic");
}
}

Trong trường hợp có một đoạn diễn giải liên tiếp trong chương trình, thay
vì sử dụng cặp dấu // để ghi chú từng câu, chúng ta sử dụng cặp dấu /* kế đến nội
dung và kết thúc dấu */ . Chẳng hạn, chúng ta khai báo hai câu diễn giải “

/*

- 91 -
NGUYỄN TRẦN MINH KHUÊ

C# Basic, C# Program
This program writes “C#, SQL Server”
to the console
*/
using System;
class Hello
{
static void Main() {
Console.WriteLine("C#, SQL Server");
}
}

Lưu ý rằng, bạn có thể ghi chú ngay trên cùng với câu lệnh của chương
trình, ví dụ như khai báo sau:

using System; // Declare namespace


class Hello /* C# Basic, C# Program */
{
static void Main() {
Console.WriteLine("C#, SQL Server");
}
}

52. DẤU HIỆU

Các dấu hiệu thường sử dụng trong chương trình C# bao gồm các ký tự
đặc biệt như dấu \, “, @.
Trong chương trình C# khi xuất chuỗi giá trị có các ký tự đặc biệt như dấu
\, “ thì bạn sử dụng thêm dấu \ để trình biên dịch biết rằng đây là chuỗi kết xuất.
Chẳng hạn, khai báo C:\test.txt:

using System;
class Class1
{
static void Test() {
Console.WriteLine("C:\\test.txt");
}
}

Hoặc khi chuỗi muốn xuất hiện có dấu ", bạn khai báo trong chương trình
C# với đấu \ trước dấu ", giả sử xuất ra màn hình chuỗi This is "C#" như sau:

using System;
class Class1
{
static void Test(bool f) {
if (f)
Console.WriteLine("This is \"C#\"");
}
}

- 92 -
NGUYỄN TRẦN MINH KHUÊ

Trong trường hợp đặt muốn đặt tên biến, class, các định danh khác trùng
với các từ khoá của C#, bạn sử dụng ký tự @ trước định danh. Chẳng hạn, khai
báo class có tên class hay biến có tên là int, bạn có thể sử dụng ký tự @ như sau:

using System;
class @class
{
public static void @static(bool @bool) {
if (@bool)
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
class Class1
{
static void M() {
cl\u0061ss.st\u0061tic(true);
}
}

Trong đó, @class có ký hiệu Unicode là cl\u0061ss và @static có ký hiệu


Unicode là st\u0061tic.
Ngoài ra, một số ký hiệu đặc biệt sử dụng trong C# phải nằm sau dấu \
như: ', ", \, 0, a, b, f, n, r, t, u, U, x, v (tương tự như trong ngôn ngữ lập trình C+
+).
Dấu Ký tự Unicode encoding
\' Single quote 0x0027
\" Double quote 0x0022
\\ Backslash 0x005C
\0 Null 0x0000
\a Alert 0x0007
\b Backspace 0x0008
\f Form feed 0x000C
\n New line 0x000A
\r Carriage return 0x000D
\t Horizontal tab 0x0009
\v Vertical tab 0x000B
Chẳng hạn, chúng ta khai báo các biến với các ký tự đặc biệt, thay vì sử
dụng dấu \ cho mỗi ký tự đặc biệt thì bạn có thể sử dụng dấu @ với khai báo dấu\
đầu tiên và bỏ qua các ký tự đặc biệt còn lại, kết quả tương ứng như sau:

- 93 -
NGUYỄN TRẦN MINH KHUÊ

string a = "hello, world";// hello, world


string b = @"hello, world";// hello, world
string c = "hello \t world";// hello world
string d = @"hello \t world";// hello \t world
string e = "Joe said \"Hello\" to me";
// Joe said "Hello" to me
string f = @"Joe said ""Hello"" to me";
// Joe said "Hello" to me
string g = "\\\\server\\share\\file.txt";
// \\server\share\file.txt
string h = @"\\server\share\file.txt";
// \\server\share\file.txt
string i = "one\ntwo\nthree";
string j = @"one
two
three";

- 94 -

También podría gustarte