chuong 2

Màu nền
Font chữ
Font size
Chiều cao dòng

NGÔN NGỮ C#

Đặng Thành Trung

GIỚI THIỆU

 Được phát triển bởi đội ngũ kỹ sư của Microsoft, dẫn đầu là Anders Hejlsberg và Scott Wiltamuth.

 Có khoảng 80 từ khóa và 20 kiểu dữ liệu dựng sẵn

 C# là ngôn ngữ lập trình hướng đối tượng và có những từ khóa hỗ trợ đầy đủ việc khai báo một lớp

 C# có các đặc trưng

 Hỗ trợ khái niệm giao diện

 Hỗ trợ kiểu cấu trúc

 Cung cấp đặc trưng hướng thành phần : property, sự kiện,

 Truy cập bộ nhớ trực tiếp dùng con trỏ

TỪ KHÓA C#

CHƯƠNG TRÌNH ĐẦU TIÊN

 Chương trình bắt đầu thực hiện từ hàm Main

 In ra màn hình

 Tên file và class không nhất thiết giống nhau

CẤU TRÚC CHƯƠNG TRÌNH

 Nếu namespace không được xác định => sử dụng namespace mặc định

 Namespace có thể chứa struct, interface, delegate và enum

 Namespace có thể được sử dụng ở các file khác

 Trường hợp đơn giản nhất: Một lớp, một file, và chỉ sử dụng namespace mặc định

MỘT CHƯƠNG TRÌNH 2 FILE

CÁC BƯỚC TẠO CHƯƠNG TRÌNH

 Xác định mục tiêu chương trình

 Xác định phương pháp giải quyết

 Tạo chương trình giải quyết

 Thực thi chương trình để xem kết quả

LỚP, ĐỐI TƯỢNG, KIỂU

 Bản chất của lập trình hướng đối tượng là tạo ra kiểu mới

 Một kiểu mới được định nghĩa bằng từ khóa class gọi là một lớp.

 Khai báo lớp trong C# không có dấu ";" ở cuối lệnh khai báo.

 Khai báo lớp trong C# không chia thành 2 phần header và definition như trong C++.

 Một thể hiện của lớp gọi là một đối tượng

PHƯƠNG THỨC

 Hai thành phần chính của lớp là

 Phương thức (Method) : các hàm được định nghĩa trong lớp

 Thuộc tính (Attribute) : các biến được khái báo trong lớp

 Hàm "Main" là một phương thức đặc biệt của lớp, xác định đầu vào của lớp.

 Giá trị của hàm Main có thể là void hoặc int.

 Mỗi chương trình có thể có nhiều hàm Main nhưng cần phải xác định chỉ dẫn biên dịch để thực thi một hàm Main cụ thể.

CHÚ THÍCH

 Chú thích nhằm mục đích giải thích các đoạn mã khác

 Chú thích là các đoạn mã chương trình không được biên dịch

 Có hai loại chú thích

 Chú thích đơn dòng, bắt đầu bằng ký tự "//"

 Chú thích đa dòng, bắt đầu bằng ký tự "/*" và kết thúc bằng ký tự "*/"

ỨNG DỤNG CONSOLE

 Ứng dụng giao tiếp với người dùng thông qua bàn phím và không có giao diện đồ họa.

NAMESPACE

 .NET có rất nhiều các lớp thư viện khác nhau.

 Các lớp được nhóm với nhau bằng các vùng tên (name space).

 Các vùng tên cũng có thể được nhóm với nhau bằng các vùng tên lớn hơn.

 Người dùng có thể tạo ra các vùng tên riêng cho các lớp tự định nghĩa.

 Để truy xuất đến các phương thức trong các lớp, trong các vùng tên, ... người ta sử dụng toán tử "."

 Vùng_tên.Vùng_tên_con....Tên_lớp...Tên_phương_thức

PHÂN BIỆT HOA THƯỜNG

 Ngôn ngữ C# phân biệt chữ hoa, chữ thường giống như C, C++

 Ví dụ : Writeline, WriteLine, WRITELINE, ... là khác nhau

 Tên biến, hàm, hằng, lớp, ... đều phân biệt chữ hoa, chữ thường

KIỂU DỮ LIỆU & TOÁN TỬ

Đặng Thành Trung

PHÂN LOẠI KIỂU

KIỂU GIÁ TRỊ & KIỂU THAM CHIẾU

CÁC KIỂU DỰNG SẴN

CHUYỂN ĐỔI KIỂU

 Một đối tượng có thể chuyển đổi từ kiểu này sang kiểu khác theo hai cách:

 Chuyển đổi ngầm định: được thực hiện tự động bởi trình biên dịch.

 Chuyển đổi tường minh: có sự can thiệp của người lập trình.

KIỂU LIỆT KÊ : enum

 Được sử dụng để liệt kê các hằng

TOÁN TỬ KIỂU ENUM

 Chương trình không kiểm tra kết quả có phải là một giá trị hợp lệ của kiểu enum không

 Chú ý:

 enum không được gán cho kiểu int, trừ khi phải ép kiểu tường minh

 enum kế thừa kiểu object (Equals, ToString, ...)

 Lớp System.enum cung cấp các phương thức : GetName, Format, GetValues,...

MỘT SỐ KIỂU MỞ RỘNG

 Kiểu xâu (string) : được sử dụng như một kiểu chuẩn string.

 Khai báo : string s ="Hello";

 Kiểu string không thể chỉnh sửa được (Nếu muốn chỉnh sửa dùng StringBuilder)

 Toán tử nối chuỗi là phép cộng "+"

 string là kiểu tham chiếu, nhưng có thể thực hiện phép so sánh

 Lớp string có nhiều phương thức hữu dụng: Length, CompareTo, IndexOf, StartsWith, Substring...

MỘT SỐ KIỂU MỞ RỘNG

 Mảng : tập hợp các phần tử có cùng kiểu

 Khai báo : int [] a; int [][] b;

 Mỗi thành phần được xác định thông qua chỉ số

 Có nhiều kiểu mảng : mảng một chiều, mảng nhiều chiều, mảng ziczắc, ...

 Danh sách : mảng có kích thước thay đổi.

 Khai báo : ArrayList a;

 Cấu trúc (struct)

 Lớp (class)

BIẾN VÀ HẰNG

 Biến là một vùng nhớ dành riêng cho một kiểu dữ liệu nào đó.

 Biến có thể được gán giá trị và có thể thay đổi giá trị trong quá trình thực hiện chương trình.

 Biến phải luôn được gán giá trị trước khi được sử dụng.

 Cú pháp khai báo biến

 <tên kiểu> <tên biến>

 Ví dụ : int x,y;

 Hằng là một biến nhưng giá trị của hằng không thể thay đổi trong quá trình thực hiện chương trình.

 Cú pháp khai báo hằng

 <const> <tên kiểu> <tên hằng> = <giá trị>

 Ví dụ : const float so_pi = 3.1415

TOÁN TỬ

 Toán tử được ký hiệu bằng một biểu tượng, dùng để thực hiện một hành động

 Toán tử gán: được ký hiệu là dấu "=", là toán tử hai ngôi làm toán hạng bên trái có giá trị bằng toán hạng bên phải.

 Ví dụ : x = y;

 Toán tử toán học : Là các toán tử thao tác số học.

 Có 5 toán tử toán học : +,-,*,/ và %

 Toán tử tăng, giảm: Thực hiện các thao tác số học và gán lại giá trị cho chính biến được tính toán

 Có 5 toán tử tăng, giảm tương ứng với 5 toán tử số học: +=, -=, *=, /=, %=

 Ví dụ : x = x + 3 tương đương với x += 3;

TOÁN TỬ

 Toán tử tăng, giảm 1: ++, --

 Ví dụ: x = x + 1 tương đương với x+=1 hoặc x++

 Có hai loại tăng, giảm 1 :

 Tăng, giảm tiền tố : ++x hoặc --x

 Tăng, giảm hậu tố : x++ hoặc x-

 Toán tử quan hệ : Dùng để so sánh giữa hai giá trị và trả về một giá trị logic kiểu bool (true hoặc false).

 == : so sánh bằng

 != : so sánh khác

 > : so sánh lớn hơn

 >= : so sánh lớn hơn hoặc bằng

 < : so sánh nhỏ hơn

 <= : so sánh nhỏ hơn hoặc bằng

TOÁN TỬ

 Toán tử logic : Dùng để kết hợp hai hoặc nhiều biểu thức logic

 && : kết hợp theo phép and

 || : kết hợp theo phép or

 ! : kết hợp theo phép not.

 Toán tử thao tác bit : Dùng để thực hiện các phép toán nhị phân

 & : phép and bit

 | : phép or bit

 ~ : phép not bit

 ^ : phép xor bit

 Toán tử ba ngôi :

 Cú pháp : <biểu thức điều kiện>?<biểu thức 1>:<biểu thức 2>

 Nếu biểu thức điều kiện đúng sẽ trả về giá trị của biểu thức 1, ngược lại trả về giá trị của biểu thức 2.

ĐỘ ƯU TIÊN TOÁN TỬ

KHAI BÁO

Đặng Thành Trung

PHẠM VI KHÁI BÁO

 Phân loại phạm vi khai báo

 namespace: khai báo class, interface, struct, enum, delegate

 class, interface, struct: khai báo trường dữ liệu, phương thức, ...

 enumeration: khai báo các hằng thuộc enum

 khối lệnh: khai báo các biến cục bộ

CÁC NGUYÊN TẮC KHAI BÁO

 Nguyên tắc về phạm vi khai báo

 Không có hai tên trùng nhau trong cùng một phạm vi và cùng một mức

 Có thể khai báo trùng tên khi ở các mức khác nhau

 Nguyên tắc về tầm hoạt động

 Tên chỉ có tác dụng trong phạm vi khai báo của nó.

 Tầm hoạt động còn bị ảnh hưởng bởi các modifier như: public, private, protected và internal.

VÍ DỤ

 Các namespace ở file khác nhau tạo lên phạm vi khai báo khác nhau

 Namespace lồng tạo nên phạm vi khai báo của riêng nó

SỬ DỤNG NAMESPACE

 Đối với các namespace ngoài

 Phải bổ sung thêm, dùng từ khoá using (e.g. using Util;)

 sử dụng tên đầy đủ (e.g. Util.Color)

 Hầu hết các chương trình phải sử dụng namespace System => using System;

CLASS, INTERFACE, STRUCT

 Phạm vi khai báo của subclass không phụ thuộc vào phạm vi khai báo của base class => có thể khai báo tên trùng nhau trong subclass và base class

KHỐI LỆNH

 Phạm vi khai báo của khối lệnh bao gồm phạm vi khai báo của các khối lệnh lồng trong nó.

 Các tham số hình thức phụ thuộc vào phạm vi khai báo của khối lệnh của phương thức.

 Các biến được sử dụng trong vòng lặp phụ thuộc vào khối lệnh của vòng lặp

 Phải khai báo biến cục bộ trước khi sử dụng chúng

KHAI BÁO BIẾN CỤC BỘ

CÂU LỆNH

Đặng Thành Trung

CÁC CÂU LỆNH ĐƠN GIẢN

 Lệnh rống

; // dấu "; " là kết thúc lệnh

 Lệnh gán

x = 3 * y + 1;

 Gọi phương thức

string s = "a,b,c";

string[] parts = s.Split(','); // viện dẫn tới phương thức của đối tượng

// (non-static)

s = String.Join(" + ", parts); // viện dẫn tới phương thức của class (static)

LỆNH IF ... ELSE ...

 Lệnh if ... else ... phân nhánh dựa trên một điều kiện duy nhất.

 else là phần tùy chọn, và chỉ được thực hiện khi điều kiện khi điều kiện bị sai

 Cú pháp :

if (biểu thức điều kiện)

<khối lệnh 1>

[else <khối lệnh 2>]

 Nếu các khối lệnh trong điều kiện if có nhiều hơn một lệnh thì chúng phải được đặt trong cặp dấu {}

LỆNH SWITCH

 Lệnh switch phân nhánh tùy theo từng giá trị của của biểu thức điều kiện

 Cú pháp :

switch (biểu thức điều kiện) {

case <giá trị 1> :

<khối lệnh 1>

<lệnh nhảy>

case <giá trị 2> :

<khối lệnh 2>

<lệnh nhảy>

...

[default :

<khối lệnh default>]

}

 default là phần tùy chọn được thực hiện khi biểu thức điều kiện không khớp với phần case nào.

 Lệnh nhảy có thể là break, goto, ...

VÍ DỤ

 Cài đặt switch với lệnh nhảy break

switch (country) {

case "England":

case "USA":

language = "English";

break;

case "Germany":

case "Austria":

case "Switzerland":

language = "German";

break;

case null:

Console.WriteLine("no country specified");

break;

default:

Console.WriteLine("don't know the language of " + country);

break;

}

LỆNH LẶP

 Lệnh while :

 Ý nghĩa : Trong khi điều kiện đúng thì làm ...

 Cú pháp :

while (biểu thức điều kiện)

<khối lệnh>

 Biểu thức điều kiện chỉ có giá trị đúng hoặc sai

 Vòng lặp while luôn kiểm tra điều kiện trước khi thực hiện khối lệnh.

 Nếu khối lệnh có nhiều hơn một lệnh thì các lệnh phải được đặt trong dặp dấu {}

LỆNH LẶP

 Lệnh do ... while :

 Ý nghĩa : Làm trong khi điều kiện đúng

 Cú pháp :

do

<khối lệnh>

while (biểu thức điều kiện)

 Biểu thức điều kiện chỉ có giá trị đúng hoặc sai

 Vòng lặp while luôn kiểm tra điều kiện trước sau khi thực hiện khối lệnh.

 Nếu khối lệnh có nhiều hơn một lệnh thì các lệnh phải được đặt trong dặp dấu {}

LỆNH LẶP

 Lệnh for :

 Gồm ba phần chính

 Khởi tạo biến đếm vòng lặp

 Kiểm tra biến đếm, nếu đúng thì thực hiện khối lệnh trong vòng lặp

 Thay đổi biến đếm

 Cú pháp :

for ([phần khởi tạo];[biểu thức điều kiện];[thay đổi bước lắp])

<khối lệnh>

Ví dụ :

for (int i = 0; i<n; i++)

sum += i;

 Nếu khối lệnh có nhiều hơn một lệnh thì các lệnh phải được đặt trong dặp dấu {}

LỆNH LẶP

 Lệnh foreach : Lặp trên một tập hợp hoặc một mảng

 Cú pháp

foreach (<kiểu tập hợp> <tên thành phần> in <tên tập hợp>)

<khối lệnh>

 Ý nghĩa : Vòng lặp sẽ duyệt qua từng phần tử của toàn bộ tập hợp hoặc mảng.

 Ví dụ :

int[] a = {3, 17, 4, 8, 2, 29};

foreach (int x in a) sum += x;

LỆNH NHẢY

 break : Dùng để "nhảy" ra khỏi lệnh lặp hoặc lệnh case.

 continue : Bỏ qua phần còn lại và tiếp tục vòng lặp tiếp theo.

 goto : Nhảy tới một nhãn xác định.

 Không nhảy vào một khối lệnh

 Không nhảy ra ngoài khối lệnh finally

LỆNH ĐƠN GIẢN TRÊN CONSOLE

 Hiển thị lên Console

 Cú pháp :

 System.Console.Write(<tham số>)

 System.Console.WriteLine(<tham số>)

 Ví dụ :

 System.Console.Write("Hello everybody.");

 System.Console.Write("x = {0}",x);

 Đọc giá trị từ bàn phím

 Cú pháp :

 int System.Console.Read();

 string System.Console.ReadLine();

 Ví dụ :

 int ch = System.Console.Read();

 string line = System.Console.ReadLine();

MẢNG

ĐẶNG THÀNH TRUNG

MẢNG

 Mảng là một tập hợp có thứ tự của những đối tượng có cùng kiểu.

 Các mảng khai báo trong C# thực chất là đối tượng của kiểu System.Array

 Cú pháp khai báo mảng:

 <kiểu dữ liệu>[] <tên mảng>

 <kiểu dữ liệu>[,] <tên mảng>

 Ví dụ :

 int[] myArray;

 Tạo thể hiện mảng:

 myArray = new int[6];

TRUY CẬP MẢNG

 Để truy cập vào mảng, dùng toán tử chỉ mục []

 Chỉ mục đầu tiên của mảng bắt đầu từ 0.

 Khi tạo một mảng có kiểu giữ liệu giá trị, mỗi thành phần sẽ chứa giá trị mặc định của kiểu dữ liệu.

 Mảng các số nguyên sẽ có giá trị ban đầu là 0

 Mảng các kiểu tham chiếu sẽ có giá trị ban đầu là null

 Để truyền kiểu mảng cho các phương thức, phải dùng từ khóa params

 Ví dụ : public void DisplayVals(params int[] val);

CÁC LOẠI MẢNG

 Mảng 1 chiều:

 int[] a = new int[3];

 int[] b = new int[] {3, 4, 5};

 int[] c = {3, 4, 5};

 SomeClass[] d = new SomeClass[10];// phần tử của mảng là tham chiếu

 SomeStruct[] e = new SomeStruct[10]; // phần tử của mảng là giá trị

 Mảng nhiều chiều

 Mảng nhiều chiều hình chữ nhật

 int[,] a = new int[2, 3];

 int[,] b = {{1, 2, 3}, {4, 5, 6}};

 int[,,] c = new int[2, 4, 2];

 Mảng nhiều chiều zíc zắc

 int[][] a = new int[2][]; // Phần tử của mảng tham chiếu tới một mảng khác

 a[0] = new int[] {1, 2, 3}; // Khởi tạo từng phần tử của mảng

 a[1] = new int[] {4, 5, 6};

CÁC LOẠI MẢNG

CÁC PHƯƠNG THỨC MẢNG

CÁC PHƯƠNG THỨC MẢNG

LỚP VÀ CẤU TRÚC

Đặng Thành Trung

LỚP

 Khai báo lớp

[Thuộc tính] [Bổ sung truy cập] class <Định danh lớp> [: Lớp cơ sở]

{

<Phần thân của lớp: bao gồm định nghĩa các thuộc tính và

phương thức hành động >

}

 Trong C#, phần kết thúc của lớp không có dấu ":" giống như trong C++. Tuy nhiên nếu người lập trình đưa vào thì chương trình dịch vẫn không báo lỗi.

 Trong C#, mọi chuyện đều xảy ra trong một lớp.

 Lớp chỉ kế thừa từ một lớp khác

 Lớp có thể cài đặt cho nhiều interface.

 Một đối tượng gọi là một thể hiện của lớp.

 Một đối tượng được cấp phát vùng nhớ trên heap

 Đối tượng phải được tạo với từ khóa new

VÍ DỤ VỀ LỚP

class Thoigian {

int nam, thang, ngay; //các thuộc tính

int gio, phut, giay;

public thoiGianHienHanh() { //một phương thức

System.Console.WriteLine("Hien thi thoi gian !");

}

}

public class Tester {

static void Main() {

Thoigian t = new Thoigian();

t.thoiGianHienHanh();

}

}

THUỘC TÍNH TRUY CẬP

 Thuộc tính truy cập quyết định khả năng truy cập vào lớp từ các yếu tố bên ngoài

 Trong C#,có các thuộc tính truy cập như sau:

 public : Không hạn chế truy cập

 private : Chỉ các thành phần bên trong lớp mới được truy cập.

 protect : Chỉ các thành phần bên trong lớp hoặc lớp kế thừa có thể truy cập.

 internal : Chỉ các thành phần của lớp cùng khối khai báo có thể truy cập

 protected internal : chỉ các thành phần của lớp cùng khối khai báo hoặc kế thừa có thể truy cập.

 Khi không khai báo rõ thuộc tính truy cập, các thành phần sẽ được xem như là private.

THUỘC TÍNH

THUỘC TÍNH TĨNH

Phụ thuộc vào class, không phụ thuộc vào đối tượng

class Rectangle {

static Color defaultColor; // mỗi class chỉ có một

static readonly int scale; // mỗi class chỉ có một

int x, y, width,height; // mỗi đối tượng có một

...

}

Hằng không được khai báo với từ khoá static

Truy nhập trong class Truy nhập từ class khác

... defaultColor ... scale ... ... Rectangle.defaultColor ... Rectangle.scale .

ĐÓNG GÓI DỮ LIỆU

 Thực hiện truy cập vào các biến thành viên của lớp thông qua các phương thức nhằm bảo mật dữ liệu của lớp

 Có hai bộ truy cập được thiết lập

 Bộ truy cập lấy dữ liệu

 Bộ truy cập thiết lập dữ liệu

 Ví dụ

ĐÓNG GÓI DỮ LIỆU

 Đóng gói dữ liệu giúp người lập trình kiểm tra trường dữ liệu trước khi sử dụng

 Đóng gói dữ liệu được sử dụng để thiết lập quyền readonly hoặc writeonly cho thuộc tính.

PHƯƠNG THỨC

Ví dụ

class C {

int sum = 0, n = 0;

public void Add (int x) {

sum = sum + x; n++;

}

public float Mean() {

return (float)sum / n;

}

}

Truy nhập trong class Truy nhập từ class khác

Add(3); C c = new C();

float x = Mean(); c.Add(3);

float x = c.Mean();

PHƯƠNG THỨC TĨNH

 Chỉ làm việc trên các thành phần dữ liệu static

class Rectangle {

static Color defaultColor;

public static void ResetColor() {

defaultColor = Color.white;

}

}

Truy nhập trong class Truy nhập từ class khác

ResetColor(); Rectangle.ResetColor();

THAM SỐ PHƯƠNG THỨC

 Một phương thức có thể có số lượng tham số tùy ý.

 Mỗi tham số phải được khai báo cùng kiểu dữ liệu

 Các tham số được xem như các biến cục bộ

 Có ba kiểu tham số :

THAM SỐ PHƯƠNG THỨC

THAM SỐ PHƯƠNG THỨC

 Tham số có số lượng thay đổi

NẠP CHỒNG PHƯƠNG THỨC

 Nạp chồng phương thức là cách khai báo các phương thức có thể trùng tên nhau.

 Các phương thức có thể khai báo trùng tên nhau nếu

 Số lượng tham số của chúng khác nhau

 Kiểu dữ liệu của các tham số là khác nhau

 Kiểu truyền tham số khác nhau

NẠP CHỒNG PHƯƠNG THỨC

 Các hàm chồng chỉ khác nhau về kiểu dữ liệu trả về không được chấp nhận

 Khai báo :

 int F();

 string F();

 Gọi hàm

 F(); //lỗi khi dịch

 Các hàm chồng sau cũng không hợp lệ

 Khai báo

 void P(int[] a) {...}

 void P(params int[] a) {...}

 Gọi hàm

 int[] a = {1, 2, 3};

 P(a);

 P(1, 2, 3);

HÀM KHỞI TẠO CỦA LỚP

 Phương thức được thực hiện khi người dùng tạo ra một đối tượng gọi là hàm khởi tạo của lớp

 Hàm khởi tạo cũng bị nạp chồng

 Trong hàm khởi tạo có thể gọi hàm khởi tạo khác, sử dụng từ khóa this

HÀM KHỞI TẠO MẶC ĐỊNH

 Nếu người dùng không định nghĩa hàm khởi tạo khi xây dựng lớp thì hệ thống sử dụng hàm khởi tạo mặc định, không có tham số.

class C { int x; }

C c = new C(); // ok

 Hàm tạo mặc định khởi tạo trường dữ liệu theo nguyên tắc sau:

số 0

enum 0

bool false

char '\0'

tham chiếu null

 Nếu class khai báo hàm tạo, thì hàm tạo mặc định sẽ không được tạo ra

class C {

int x;

public C(int y) { x = y; }

}

C c1 = new C(); // lỗi khi dịch chương trình

C c2 = new C(3); // ok

HÀM KHỞI TẠO TĨNH

 Không có tham số và không sử dụng từ khoá public hoặc private

 Mỗi class/struct chỉ có một hàm tạo static

 Nó chỉ được viện dẫn một lần trước khi class/struct được sử dụng.

 Được sử dụng để khởi tạo các trường dữ liệu static

HÀM KHỞI TẠO SAO CHÉP

 Hàm khởi tạo sao chép thực hiện sao chép tất cả các biến từ một đối tượng đã có và cùng một kiểu dữ liệu.

TỪ KHÓA this

 Từ khóa this được dùng để tham chiếu đến thể hiện hiện thời của một đối tượng

 Từ khóa this được xem là con trỏ ẩn đến tất cả các phương thức không có thuộc tính tĩnh trong một lớp.

 Tham chiếu this được sử dụng theo ba cách

 Sử dụng khi các biến thành viên bị che lấp bởi tham số đưa vào

 Sử dụng tham chiếu this để truyền đối tượng hiện hành vào một tham số của một phương thức đối tượng khác

 Sử dụng tham chiếu this như là mảng chỉ mục (indexer)

HÀM HỦY CỦA LỚP

 Được gọi trên một đối tượng trước khi bị xoá bởi garbage collector.

 Hàm huỷ của lớp cơ sở được tự động gọi vào cuối cùng

 Không sử dụng từ khoá public hoặc private.

 Struct không cần có hàm huỷ

 Ví dụ

class Test {

~Test() {

... cleanup actions ...

}

}

INDEXER

 Indexer được sử dụng để đánh chỉ số cho một tập hợp

class File {

FileStream s;

public int this [int index] {

get {s.Seek(index, SeekOrigin.Begin);

return s.ReadByte();

}

set {s.Seek(index, SeekOrigin.Begin);

s.WriteByte((byte)value);

}

}

}

Sử dụng

File f = ...;

int x = f[10]; // gọi phương thức f.get(10)

f[10] = 'A'; // gọi phương thức f.set(10, 'A')

 Có thể bỏ qua phương thức get hoặc set (read-only hoặc write-only)

 Indexer có thể bị chồng với nhiều kiểu chỉ số khác nhau

INDEXER

class MonthlySales {

int[] apples = new int[12];

int[] bananas = new int[12];

...

public int this[int i] {

// bỏ qua phương thức set => read-only

get { return apples[i-1] + bananas[i-1]; }

}

public int this[string month] {

// indexer bị chồng

get {

switch (month) {

case "Jan": return apples[0] + bananas[0];

case "Feb": return apples[1] + bananas[1];

...

}

}

}

}

MonthlySales sales = new MonthlySales();

Console.WriteLine(sales[1] + sales["Feb"]);

CẤU TRÚC

 Là một kiểu đơn giản, có kích thước nhỏ, dùng để thay thế cho lớp.

 Các đối tượng được cấp phát trên stack (struct là kiểu giá trị)

 Khai báo

[thuộc tính] [bổ sung truy cập] struct <tên cấu trúc> [:<danh sách giao diện>]{

[<thành viên của cấu trúc>]

}

 Ví dụ

struct Point {

int x, y;

public Point(int x, int y) { this.x = x; this.y = y; }

public MoveTo (int x, int y) {...}

}

CẤU TRÚC

 Cấu trúc có thể được cấp phát với từ khóa new

Point p; // các trường dữ liệu của p chưa được khởi tạo

Point q = new Point();

 Các trường dữ liệu không được khởi tạo lúc khai báo

struct Point {

int x = 0; // lỗi dịch chương trình

}

 Cấu trúc không hỗ trợ việc thừa kế nhưng có thể cài đặt cho giao diện

 Cấu trúc không có bộ hủy và bộ khởi tạo mặc định tùy chọn

HÀM KHỞI TẠO CỦA struct

 Chương trình dịch sẽ tạo ra hàm tạo mặc định, không có tham số cho tất cả các struct (kể cả struct đã khai báo hàm tạo)

 Không cần phải khai báo hàm tạo không có tham số cho struct

 Hàm tạo của struct phải khởi tạo tất cả các trường dữ liệu

CLASS & STRUCT

Class System.Object

 Là class cơ sở của tất cả các kiểu tham chiếu

class Object {

public virtual bool Equals(object o) {...}

public virtual string ToString() {...}

public virtual int GetHashCode() {...}

...

}

 Có thể được sử dụng như các kiểu chuẩn: object

object obj; // chương trình dịch sẽ ánh xạ kiểu object sang kiểu System.Object

 Có thể gán đối tượng của kiểu Object cho bất kỳ kiểu tham chiếu nào

obj = new Rectangle();

obj = new int[3];

 Các phương thức của Object có thể làm việc trên bất kỳ kiểu tham chiếu nào

void Push(object x) {...}

Push(new Rectangle());

Push(new int[3]);

Boxing và Unboxing

 Các kiểu giá trị (int, struct, enum) tương thích với kiểu object

Boxing :

object obj = 3;

gói giá trị 3 vào một đối tượng trên heap (wrap)

Unboxing :

int x = (int) obj;

trả giá trị từ đối tượng trên heap (unwrap)

Boxing và Unboxing

class Queue {

...

public void Enqueue(object x) {...}

public object Dequeue() {...}

...

}

Queue có thể sử dụng cả kiểu tham chiếu và kiểu giá trị

Queue q = new Queue();

q.Enqueue(new Rectangle());

q.Enqueue(3);

Rectangle r = (Rectangle) q.Dequeue();

int x = (int) q.Dequeue();

NẠP CHỒNG TOÁN TỬ

Đặng Thành Trung

VÍ DỤ

 Xây dựng lớp phân số có thể thực hiện các phép toán số học : cộng, trừ, nhân chia, ...

 Có hai cách xây dựng các phép toán

 Dùng phương thức :

Faction theSum,firstFraction, secondFraction;

the Sum = firstFraction.add(secondFraction);

 Dùng toán tử

Faction theSum,firstFraction, secondFraction;

the Sum = firstFraction+secondFraction;

SỬ DỤNG TỪ KHÓA operator

 Các toán tử là các phương thức tĩnh. Giá trị trả về thể hiện kết quả của một toán tử và các tham số là toán hạng.

 Tạo một toán tử cho một lớp tức là thực hiện việc lạp chồng.

 Toán tử nạp chồng được khai báo sử dụng từ khóa operator

 Ví dụ

class Fraction {

int x, y;

public Fraction (int x, int y) {this.x = x; this.y = y; }

public static Fraction operator + (Fraction a, Fraction b) {

return new Fraction(a.x * b.y + b.x * a.y, a.y * b.y);

}

}

 Sử dụng

Fraction a = new Fraction(1, 2);

Fraction b = new Fraction(3, 4);

Fraction c = a + b; // c.x == 10, c.y == 8

MỘT SỐ LUẬT

 Định nghĩa những toán tử trong kiểu dữ liệu giá trị, kiểu do ngôn ngữ xây dựng sẵn

 Cung cấp những phương thức nạp chồng toán tử chỉ bên trong của lớp nơi mà những phương thức được định nghĩa.

 Sử dụng tên và những ký hiệu qui ước mô tả trong Common Language Specification (CLS)

 Phải cung cấp các phương thức thay thế cho toán tử nạp chồng

MỘT SỐ LUẬT

MỘT SỐ LUẬT

MỘT SỐ LUẬT

TOÁN TỬ SO SÁNH BẰNG

 Nếu nạp chồng toán tử so sánh bằng (==), nên phủ quyết phương thức ảo Equals của lớp object và chuyển lại cho toán tử so sánh bằng thực hiện.

 Ví dụ

public overide bool Equals(object o)

{

if ( !(o is Fraction) ) return false;

return this == (Fraction) o;

}

 Nạp chồng toán tử có tính đối xứng, tức là nếu toán tử so sánh bằng được nạp chồng thì cũng phải nạp chồng toán tử không bằng (!=).

 Nếu toán tử (==) và (!=) mà được nạp chồng và phương thức Equals không được nạp chồng thì chương trình sẽ cảnh báo.

VÍ DỤ

using System;

public class Fraction

{

public Fraction(int numerator,int denominator)

{

Console.WriteLine("In Fraction Constructor( int, int) ");

this.numerator = numerator;

this.denominator = denominator;

}

public Fraction(int wholeNumber)

{

Console.WriLine("In Fraction Constructor( int )");

numerator = wholeNumber;

denominator = 1;

}

public static implicit operator Fraction( int theInt )

{

Console.WriteLine(" In implicit conversion to Fraction");

return new Fraction( theInt );

}

VÍ DỤ

public static explicit operator int( Fraction theFraction )

{

Console.WriteLine("In explicit conversion to int");

return theFraction.numerator / theFraction.denominator;

}

public static bool operator == ( Fraction lhs, Fraction rhs)

{

Console.WriteLine("In operator ==");

if ( lhs.numerator == rhs.numerator &&

lhs.denominator == rhs.denominator ) return true;

// thực hiện khi hai phân số không bằng nhau

return false;

}

public static bool operator != ( Fraction lhs, Fraction rhs)

{

Console.WriteLine("In operator !=");

return !( lhs == rhs );

}

public override bool Equals( object o )

{

Console.WriteLine("In method Equals");

if ( !(o is Fraction )) return false;

return this == ( Fraction ) o;

}

VÍ DỤ

public static Fraction operator+( Fraction lhs, Fraction rhs )

{

Console.WriteLine("In operator +");

if (lhs.denominator == rhs.denominator )

return new Fraction( lhs.numerator + rhs.numerator, lhs.denominator );

//thực hiện khi hai mẫu số khộng bằng nhau

int firstProduct = lhs.numerator * rhs.denominator;

int secondProduct = rhs.numerator * lhs.denominator;

return new Fraction( firstProduct + secondProduct,

lhs.denominator * rhs.denominator);

}

public override string ToString()

{

string s = numerator.ToString() + "/" + denominator.ToString();

return s;

}

//biến thành viên lưu tử số và mẫu số

private int numerator;

private int denominator;

}

VÍ DỤ

public class Tester

{

static void Main()

{

Fraction f1 = new Fraction( 3, 4);

Console.WriteLine("f1:{0}",f1.ToString());

Fraction f2 = new Fraction( 2, 4);

Console.WriteLine("f2:{0}",f2.ToString());

Fraction f3 = f1 + f2;

Console.WriteLine("f1 + f2 = f3:{0}",f3.ToString());

Fraction f4 = f3 + 5;

Console.WriteLine("f4 = f3 + 5:{0}",f4.ToString());

Fraction f5 = new Fraction( 2, 4);

if( f5 == f2 )

{

Console.WriteLine("f5:{0}==f2:{1}",

f5.ToString(), f2.ToString());

}

}

}

THỪA KẾ VÀ ĐA HÌNH

Đặng Thành Trung

ĐẶC BIỆT HÓA & TỔNG QUÁT HÓA

 Lớp và các thể hiện của lớp (đối tượng) tuy không cùng tồn tại trong cùng một khối nhưng chúng tồn tại trong một mạng lưới các quan hệ phụ thuộc lẫn nhau.

 Quan hệ là một (is-a) là một sự đặc biệt hóa

 Mèo là một loài động vật có vú. Nó có tất cả các đặc tính của một loài động vật có vú và có thêm các thuộc tính đặc trưng riêng của họ nhà mèo.

 Quan hệ đặc biệt hóa & tổng quát hóa là đối ngẫu và phân cấp

 Tạo ra cây quan hệ

 Di chuyển đi lên là tổng quát hóa, ngược lại di chuyển đi xuống là đặc biệt hóa.

KẾ THỪA

 Quan hệ đặc biệt hóa được thực thi bằng cách sử dụng sự kế thừa.

 Trong ngôn ngữ C#, để tạo một lớp kế thừa từ lớp khác, thêm dấu ":" vào sau tên lớp đó

 public class Meo : Dongvatcovu

 Lớp kế thừa (Meo) gọi là lớp dẫn xuất

 Lớp được kế thừa (Dongvatcovu) gọi là lớp được dẫn xuất hoặc lớp cơ sở.

 Lớp dẫn xuất kế thừa tất cả các thành phần của lớp cơ sở.

 Lớp dẫn xuất có thể tạo phương thức mới bằng việc đánh dấu với từ khóa new

VÍ DỤ

class A { // lớp cơ sở

public int a;

public A() {...}

public void F() {...}

}

class B : A { // lớp con (kế thừa từ A, mở rộng A)

int b;

public B() {...}

public void G() {...}

}

 Lớp B kế thừa thuộc tính a và phương thức F, bổ sung thêm thuộc tính b và phương thức G

 Hàm tạo không được kế thừa

 Các phương thức được kế thừa có thể chồng lớp con

 Một lớp chỉ được kế thừa từ lớp khác nhưng có thể cài đặt cho nhiều interface.

 Một lớp chỉ có thể kế thừa từ một lớp khác không phải là struct

 Một lớp không có lớp cơ sở tường minh sẽ kế thừa từ lớp object

GÁN VÀ KIỂM TRA KIỂU

Khai báo

class A {...}

class B : A {...}

class C: B {...}

Lệnh gán

A a = new A(); // kiểu static của biến a là kiểu khi khai báo (A)

// kiểu dynamic type của biến a là kiểu của đối tượng được khởi tạo (A)

a = new B(); // kiểu dynamic là B

a = new C(); // kiểu dynamic là C

B b = a; // lỗi khi dịch chương trình

Kiểm tra kiểu khi thực thi (Toán tử is)

a = new C();

if (a is C) ... // true, nếu kiểu dynamic của a là C hoặc subclass của C

if (a is B) ... // true

if (a is A) ... // true

a = null;

if (a is C) ... // false

ÉP KIỂU

Ép kiểu

A a = new C();

B b = (B) a; // đúng, nếu a có kiểu dynamic là B hoặc subclass của B

C c = (C) a;

a = null;

c = (C) a; // đúng, c = null

Toán tử as

A a = new C();

B b = a as B; // if (a is B) b = (B)a; else b = null;

C c = a as C;

a = null;

c = a as C; // c == null

CHỒNG PHƯƠNG THỨC

Chỉ những phương thức được khai báo với từ khoá virtual mới được chồng.

class A {

public void F() {...} // F không được chồng

public virtual void G() {...} // Có thể chồng G trong subclass

}

Các phương thức chồng được khai báo với từ khoá override

class B : A {

public void F() {...} // nên sử dụng từ khoá new

public void G() {...} // nên sử dụng từ khoá new

public override void G() { // ok: chồng toán tử G

... base.G(); // gọi G() của lớp cơ sở

}

}

 Thuộc tính và indexer cũng được chồng.

 Phương thức static không được chồng

GÁN ĐỘNG

class A {

public virtual void WhoAreYou() {Console.WriteLine("I am an A"); }

}

class B : A {

public override void WhoAreYou() { Console.WriteLine("I am a B"); }

}

Thông điệp viện dẫn phương thức phụ thuộc vào kiểu dynamic của đối tượng.

A a = new B();

a.WhoAreYou(); // "I am a B"

Ưu điểm: mọi phương thức có thể làm việc với A đều làm việc được với B

void Use (A x) {

x.WhoAreYou();

}

Use(new A()); // "I am an A"

Use(new B()); // "I am a B"

ẨN

Trong subclass, các thành phần được khai báo với từ khoá new sẽ ẩn tất cả các thành phần có cùng tên và dấu hiệu trong baseclass.

class A {

public int x;

public void F() {...}

public virtual void G() {...}

}

class B : A {

public new int x;

public new void F() {...}

public new void G() {...}

}

B b = new B();

b.x = ...; // truy nhập tới B.x

b.F(); ... b.G(); // gọi tới B.F và B.G

((A)b).x = ...; // truy nhập tới A.x

((A)b).F(); ... ((A)b).G(); // gọi tới A.F và A.G

VÍ DỤ

class Animal {

public virtual void WhoAreYou() { Console.WriteLine("I am an animal"); }

}

class Cat : Animal {

public override void WhoAreYou() { Console.WriteLine("I am a cat"); }

}

Animal pet = new Cat();

pet.WhoAreYou(); // "I am a cat"

HÀM TẠO VÀ THỪA KẾ

PROTECTED VÀ INTERNAL

protected có thể được truy nhập trong cùng class và các subclass của nó

internal có thể được truy nhập trong cùng assembly

protected internal có thể được truy nhập trong cùng class và các subclass của nó, nhưng phải thuộc cùng một assembly

Ví dụ

class Stack {

protected int[] values = new int[32];

protected int top = -1;

public void Push(int x) {...}

public int Pop() {...}

}

class BetterStack : Stack {

public bool Contains(int x) {

foreach (int y in values) if (x == y) return true;

return false;

}

}

class Client {

Stack s = new Stack();

... s.values[0] ... // lỗi khi dịch

}

LỚP TRỪU TƯỢNG

Ví dụ

abstract class Stream {

public abstract void Write(char ch);

public void WriteString(string s) { foreach (char ch in s) Write(s); }

}

class File : Stream {

public override void Write(char ch) {... ghi ch vào bộ nhớ ...}

}

Chú ý

 Các phương thức abstract không có phần cài đặt.

 Nếu một lớp có phương thức abstract (do khai báo hoặc do kế thừa) thì lớp đó phải là lớp trừu tượng.

 Không thể tạo ra đối tượng của lớp trừu tượng

THUỘC TÍNH VÀ INDEXER TRỪU TƯỢNG

Ví dụ

abstract class Sequence {

public abstract void Add(object x); // phương thức

public abstract string Name { get; } // thuộc tính

public abstract object this [int i] { get; set; } // indexer

}

class List : Sequence {

public override void Add(object x) {...}

public override string Name { get {...} }

public override object this [int i] { get {...} set {...} }

}

Chú ý

 Các thuộc tính và indexer được chồng phải có cùng các phương thức get/set tương tự như trong baseclass

LỚP CÔ LẬP (SEALED CLASS)

Ví dụ

sealed class Account : Asset {

long val;

public void Deposit (long x) { ... }

public void Withdraw (long x) { ... }

...

}

Chú ý

 Không thể kế thừa từ sealed class, nhưng sealed class vẫn kế thừa từ lớp khác.

 Cũng có thể sử dụng từ khoá sealed với các phương thức

LỚP TỔNG QUAN (System.object)

System.Object là baseclass của tất cả các lớp

class Object {

protected object MemberwiseClone() {...}

public Type GetType() {...}

public virtual bool Equals (object o) {...}

public virtual string ToString() {...}

public virtual int GetHashCode() {...}

}

Sử dụng trực tiếp

Type t = x.GetType(); trả về kiểu được khai báo của x

object copy = x.MemberwiseClone(); tạo ra bản sao

Chồng trong subclass:

x.Equals(y) so sánh giá trị của x và y

x.ToString() trả về xâu biểu diễn x

int code = x.getHashCode(); trả về mã băm của x

VÍ DỤ VỀ LỚP System.object

class Fraction {

int x, y;

public Fraction(int x, int y) { this.x = x; this.y = y; }

...

public override string ToString() { return String.Format("{0}/{1}", x, y); }

public override bool Equals(object o) { Fraction f = (Fraction)o; return f.x == x && f.y == y; }

public override int GetHashCode() { return x ^ y; }

public Fraction ShallowCopy() { return (Fraction) MemberwiseClone(); }

}

class Client {

static void Main() {

Fraction a = new Fraction(1, 2);

Fraction b = new Fraction(1, 2);

Fraction c = new Fraction(3, 4);

Console.WriteLine(a.ToString()); // 1/2

Console.WriteLine(a); // 1/2 (ToString được gọi tự động)

Console.WriteLine(a.Equals(b)); // true

Console.WriteLine(a == c); // false

Console.WriteLine(a.GetHashCode()); // 3

a = c.ShallowCopy();

Console.WriteLine(a); // 3/4

}

}

INTERFACE - GIAO DIỆN

Đặng Thành Trung

CÚ PHÁP

public interface IList : ICollection, IEnumerable {

int Add (object value); // methods

bool Contains (object value);

...

bool IsReadOnly { get; } // property

...

object this [int index] { get; set; } // indexer

}

 Interface là abstract class; không có phần cài đặt.

 Có thể chứa methods, properties, indexers and events

(không chứa trường dữ liệu, hằng, hàm tạo, hàm huỷ, toán tử, kiểu lồng).

 Các thành phần của interface là public abstract (virtual).

 Các thành phần của interface không thể là static.

 Class và struct có thể cài đặt nhiều interface.

 Interface có thể mở rộng các interface khác.

interface được cài đặt bởi class và struct

class MyClass : MyBaseClass, IList, ISerializable {

public int Add (object value) {...}

public bool Contains (object value) {...}

...

public bool IsReadOnly { get {...} }

...

public object this [int index] { get {...} set {...} }

}

 Một class chỉ kế thừa từ một baseclass, nhưng có thể cài đặt cho nhiều interface.

Một struct không kế thừa, nhưng có thể cài đặt cho nhiều interface.

 Tất cả các thành phần của interface (method, property, indexer) đều phải được cài đặt hoặc được thừa kế.

 Khi cài đặt các phương thức của interface không cần sử dụng từ khoá override, có thể sử dụng từ khoá virtual hoặc abstract .

 Nếu phương thức Add của MyClass được chồng trong các subclass thì nó nên được khai báo với từ khoá virtual .

THỰC THI GIAO DIỆN

Gán: MyClass c = new MyClass();

IList list = c;

Gọi phương thức: list.Add("Tom"); // gán động => myClass.Add

Kiểm tra kiểu: if (list is MyClass) ... // true

if (list is ISerializable) ... // true

Ép kiểu: c = list as MyClass;

c = (MyClass) list;

ISerializable ser = (ISerializable) list;

VÍ DỤ

interface ISimpleReader {

int Read();

}

interface IReader : ISimpleReader {

void Open(string name);

void Close();

}

class Terminal : ISimpleReader {

public int Read() { ... }

}

class File : IReader {

public int Read() { ... }

public void Open(string name) { ... }

public void Close() { ... }

}

// null có thể được gán cho các biến của các kiểu interface

ISimpleReader sr = null; sr = new Terminal();

sr = new File();

IReader r = new File();

sr = r;

XUNG ĐỘT TÊN

Xảy ra khi có hai interface cơ sở có phương thức cùng tên

interface I1 {

void F();

}

interface I2 {

void F();

}

class B : I1, I2 {

//-----cài đặt phương thức F của class B

public void F() { Console.WriteLine("B.F"); }

//----- cài đặt phương thức F cho từng interface

void I1.F() { Console.WriteLine("I1.F"); }

void I2.F() { Console.WriteLine("I2.F"); } // phải là public

}

B b = new B();

b.F(); // B.F

I1 i1 = b;

i1.F(); // I1.F

I2 i2 = b;

i2.F(); // I2.F

DELEGATE - ỦY QUYỀN

Đặng Thành Trung

delegate

 delegate là kiểu dữ liệu đặc biệt, có khả năng lưu trữ một tham chiếu tới phương thức có dấu hiệu cụ thể (tức là các tham số và kiểu trả về của phương thức).

 delegate có thể viện dẫn các phương thức một cách động khi sự kiện xảy ra.

 delegate không quan tâm tới những lớp đối tượng mà nó tham chiếu tới.

delegate LÀ KIỂU PHƯƠNG THỨC

Khai báo kiểu delegate

delegate void Notifier (string sender);// tương tự khai báo phương thức

// sử dụng từ khoá delegate

Khai báo biến delegate

Notifier greetings;

Gán một phương thức cho biến delegate

void SayHello(string sender) {

Console.WriteLine("Hello from " + sender);

}

greetings = new Notifier(SayHello);

Lời gọi biến delegate

greetings("John"); // viện dẫn phương thức SayHello("John") => "Hello from John"

GÁN PHƯƠNG THỨC KHÁC NHAU

 Tất cả các phương thức phù hợp với delegate đều có thể được gán với biến delegate đó

void SayGoodBye(string sender) {

Console.WriteLine("Good bye from " + sender);

}

greetings = new Notifier(SayGoodBye);

greetings("John");// SayGoodBye("John") => "Good bye from John"

Chú ý

 Biến delegate có thể được gán giá trị null (không có phương thức nào được gán cho nó).

 Nếu biến delegate bằng null thì sẽ không được gọi

TẠO GIÁ TRỊ CỦA delegate

new DelegateType (obj.Method)

 Biến delegate chứa phương thức và đối tượng nhận, nhưng không chứa tham số

new Notifier(myObj.SayHello);

 Đối tượng có thể là this (và có thể bỏ qua)

new Notifier(SayHello);

 Phương thức có thể là static. Trong trường hợp này, tên của class phải được thay thế cho đối tượng.

new Notifier(MyClass.StaticSayHello);

 Phương thức không thể là abstract, nhưng có thể là virtual, override, hoặc new.

 Dấu hiệu của phương thức phải trùng với dấu hiệu của DelegateType

- số lượng tham số

- kiểu dữ liệu của tham số (bao gồm cả kiểu trả về)

- kiểu truyền tham số (ref, out, value)

MULTICAST delegate

 Biến delegate có thể chứa nhiều giá trị cùng một thời điểm

Notifier greetings;

greetings = new Notifier(SayHello);

greetings += new Notifier(SayGoodBye);

greetings("John"); // "Hello from John"

// "Good bye from John"

greetings -= new Notifier(SayHello);

greetings("John"); // "Good bye from John"

 Chú ý

 Nếu multicast delegate là một hàm, thì sẽ trả về giá trị của lời gọi cuối cùng

 Nếu multicast delegate có tham số out, tham số của lời gọi cuối cùng sẽ được trả về. Tham số ref được truyền qua tất cả các phương thức.

Event là delegate đặc biệt

class Model {

public event Notifier notifyViews;

public void Change() { ... notifyViews("Model"); }

}

class View {

public View(Model m) { m.notifyViews += new Notifier(Update); }

void Update(string sender) { Console.WriteLine(sender + " was changed"); }

}

class Test {

static void Main() {

Model model = new Model();

new View(model); new View(model); ...

model.Change();

}

}

Tại sao phải sử dụng event để thay thế cho các biến delegate khác?

 Chỉ class khai báo event thì mới được kích hoạt nó

 Các class khác có thể thay đổi event bằng toán tử += hoặc -= (nhưng không sử dụng toán tử =)

BẮT SỰ KIỆN

Các delegate dùng để bắt sự kiện có dấu hiệu như sau:

delegate void SomeEvent (object source, MyEventArgs e);

 Kiểu trả về: void

 Tham số thứ nhất: Đối tượng gửi sự kiện (kiểu object)

 Tham số thứ hai: sự kiện (subclass của System.EventArgs)

public class EventArgs {

public static readonly EventArgs Empty;

}

VÍ DỤ

public delegate void KeyEventHandler (object sender, KeyEventArgs e);

public class KeyEventArgs : EventArgs {

public virtual bool Alt { get {...} } // true nếu nhấn phím Alt

public virtual bool Shift { get {...} } // true nếu nhấn phím Shift

public bool Control { get {...} }// true nếu nhấn phím Ctrl

public bool Handled { get{...} set {...} } // cho biết có bắt được sự kiện không

public int KeyValue { get {...} }// mã phím

...

}

class MyKeyEventSource {

public event KeyEventHandler KeyDown;

public KeyPressed() {

KeyDown(this, new KeyEventArgs(...));

}

}

class MyKeyListener {

public MyKeyListener(...) { keySource.KeyDown += new KeyEventHandler(HandleKey);}

void HandleKey (object sender, KeyEventArgs e) {...}

}

EXCEPTION - NGOẠI LỆ

Đặng Thành Trung

LỆNH try

FileStream s = null;

try {

s = new FileStream(curName, FileMode.Open);

...

} catch (FileNotFoundException e) {

Console.WriteLine("file {0} not found", e.FileName);

} catch (IOException) {

Console.WriteLine("some IO exception occurred");

} catch {

Console.WriteLine("some unknown error occurred");

} finally {

if (s != null) s.Close();

}

 Mệnh đề catch được kiểm tra theo thứ tự.

 Mệnh đề finally luôn luôn được thực hiện (nếu xuất hiện)

 Tên của Exception trong mệnh đề catch có thể được bỏ qua

 Kiểu của Exception phải thừa kế từ System.Exception.

System.Exception

Thuộc tính

e.Message thông báo lỗi

e.StackTrace vết lưu stack lời gọi phương thức

e.Source ứng dụng hoặc đối tượng trả về Exception

...

Phương thức

e.ToString() Trả về tên của Exception và StackTrace

...

TRẢ VỀ Exception

 Do các thao tác không hợp lệ (ngoại lệ không tường minh)

 Chia cho 0

 Tràn chỉ số

 Truy nhập vào tham số có giá trị null

 ...

 Do lệnh throw (ngoại lệ tường minh)

throw new FunnyException(10);

class FunnyException : ApplicationException {

public int errorCode;

public FunnyException(int x) { errorCode = x; }

}

 (Do lời gọi tới một phương thức có trả ra ngoại lệ nhưng không được bắt)

s = new FileStream(...);

CẤU TRÚC EXCEPTION

 Exception

 SystemException

ArithmeticException

DivideByZeroException

OverflowException

...

NullReferenceException

IndexOutOfRangeException

InvalidCastException

...

 ApplicationException

... user-defined exceptions

...

 IOException

FileNotFoundException

DirectoryNotFoundException

...

 WebException

...

TÌM KIẾM MỆNH ĐỀ catch

 Chuỗi lời gọi sẽ được thực hiện cho đến khi có một phương thức có mệnh đề catch tương ứng được tìm thấy

 Nếu không tìm thấy, chương trình sẽ báo lỗi

EXCEPTION TRONG delegate

 Trong quá trình tìm kiếm mệnh đề catch, delegate cũng được coi như các hàm

exception trong multicast delegate

 Nếu Exc1 được trả ra từ G() thì F() sẽ bắt và sau đó gọi H()

 Nếu Exc2 được trả ra từ G() thì hàm Main() sẽ bắt và H() không được gọi nữa.

THƯ VIỆN

Đặng Thành Trung

TỔNG QUAN

Math

public sealed class Math {

public const double PI = 3.14....;

public const double E = 2.71...;

public static T Abs(T val); // T là kiểu: sbyte, short, int, long, float, double, decimal

public static T Sign(T val);

public static T1 Min(T1 x, T1 y); // T1, T là kiểu: byte, ushort, uint, ulong

public static T1 Max(T1 x, T1 y);

public static double Round(double x);

public static double Floor(double x);

public static double Ceiling(double x);

public static double Sqrt(double x);

public static double Pow(double x, double y); // xy

public static double Exp(double x) // ex

public static double Log(double x); // logex

public static double Log10(double x); // log10x

public static double Sin(double x); // góc tính theo radian

public static double Cos(double x);

public static double Tan(double x);

public static double Asin(double x);

public static double Acos(double x);

public static double Atan(double x);

}

Random

public class Random {

public Random();

public Random(int seed);

public virtual int Next(); // 0 <= res < int.MaxVal

public virtual int Next(int x); // 0 <= res < x

public virtual int Next(int x, int y); // x <= res < y

public virtual double NextDouble(); // 0.0 <= res < 1.0

public virtual void NextBytes(byte[] b); // các phần tử của mảng b là số ngẫu nhiên

}

String

public sealed class String : ICloneable, IComparable, IEnumerable {

public String(char[] a);

public String(char[] a, int start, int len);

public static string Copy(string s);

public static string Format(String s, params object[]);

public static string Join(string separator, string[] parts);

public static bool operator ==(bool a, bool b);

public static bool operator !=(bool a, bool b);

public int Length { get; }

public char this[int i] { get; }

public override bool Equals(object o);

public int CompareTo(object o);

public static int CompareOrdinal(string a, string b);

public void CopyTo(int from, char[] dest, int to, int len);

public bool StartsWith(string s);

public bool EndsWith(string s);

public int IndexOf(T s); // T ... string, char

public int LastIndexOf(T s);

public string Substring(int pos);

public string Substring(int pos, int len);

public string[] Split(params char[]);

public char[] ToCharArray();

...

}

Chuyển đổi giữa string và số

public sealed class Convert { // namespace System

public static string ToString(T x); // T là kiểu số bất kỳ

public static bool ToBoolean(string s);

public static byte ToByte(string s);

public static sbyte ToSByte(string s);

public static char ToChar(string s);

public static short ToInt16(string s);

public static int ToInt32(string s);

public static long ToInt64(string s);

public static ushort ToUInt16(string s);

public static uint ToUInt32(string s);

public static ulong ToUInt64(string s);

public static float ToSingle(string s);

public static double ToDouble(string s);

public static decimal ToDecimal(string s);

...

}

string s = Convert.ToString(123); // "123"

s = 123.ToString(); // "123"

int i = Convert.ToInt32(s); // 123

StringBuilder

public sealed class StringBuilder { // namespace System.Text

public StringBuilder();

public StringBuilder(int initCapacity);

public StringBuilder(string s);

public StringBuilder(string s, int from, int len);

public int Length { get; set; }

public int Capacity { get; set; }

public char this[int i] { get; set; }

public StringBuilder Append(T x); // T là kiểu string hoặc kiểu số

public StringBuilder Insert(int pos, T x);

public StringBuilder Remove(int pos, int len);

public StringBuilder Replace(T x, T y); // T là kiểu string, char

public bool Equals(object x);

public string ToString();

...

}

Ví dụ

StringBuilder b = new StringBuilder("A.C");

b.Insert(2, "B.");

b.Replace('.', '/');

Console.WriteLine(b.ToString()); // A/B/C

Collection class

Array

Tất cả các mảng đều kế thừa từ lớp Array

public abstract class Array : IList, ICloneable, IEnumerable{ // namespace System

public int Length { get; } // tổng số các phần tử trong các chiều

public int Rank { get; } // tổng số các chiều

public static void Clear(Array a, int pos, int length);

public static void Copy(Array src, int from, Array dst, int to, int len);

public static int IndexOf(Array a, object x);

public static int LastIndexOf(Array a, object x);

public static void Reverse(Array a);

public static void Sort(Array a);

public static int BinarySearch(Array a, object x);

public virtual object Clone();

public virtual bool Equals(object x);

public int GetLength(int dimension);

...

}

Ví dụ

int[] a = {17, 3, 5, 9, 6};

Array.Sort(a);

Array.Reverse(a);

foreach (int x in a) Console.Write("{0} ", x); // 17 9 6 5 3

ArrayList

Mảng động

public class ArrayList : IList, IEnumerable, ICloneable { // namespace System.Collections

public ArrayList();

public ArrayList(int initCapacity);

public ArrayList(ICollection c);

public virtual int Count { get; }

public virtual int Capacity { get; set; }

public virtual object this[int i] { get; set; }

public virtual void Clear();

public virtual int Add(object x);

public virtual void Insert(int pos, object x);

public virtual void Remove(object x);

public virtual void RemoveAt(int pos);

public virtual object Clone();

public virtual bool Equals(object x);

public virtual bool Contains(object x);

public virtual int IndexOf(object x);

public virtual void Reverse();

public virtual void Sort();

public virtual int BinarySearch(object x);

...

}

Ví dụ ArrayList

using System;

using System.Collections;

class Test {

static void Main(string[] arg) {

ArrayList a = new ArrayList();

foreach (string s in arg) a.Add(s);

a.Sort();

Console.Write("a = ");

for (int i = 0; i < a.Count; i++) Console.Write("{0} ", a[i]);

Console.WriteLine();

int pos = a.BinarySearch("Tom");

if (pos >= 0)

Console.WriteLine("Tom found at {0}", pos);

else

Console.WriteLine("Tom not found");

}

}

Aufruf: Test John Tom Alice Charly

Ausgabe:

a = Alice Charly John Tom

Tom found at 3

ListDictionary

Tương tự như danh sách liên lết

public class ListDictionary : IDictionary, IEnumerable { // System.Collections.Specialized

public ListDictionary();

public int Count { get; }

public ICollection Keys { get; }

public ICollection Values { get; }

public object this[object key] { get; set; }

public void Clear();

public void Add(object key, object value);

public void Remove(object key);

public bool Contains(object key);

public virtual bool Equals(object x);

public IDictionaryEnumerator GetEnumerator();

...

}

Ví dụ

ListDictionary population = new ListDictionary();

population["Vienna"] = 1592600;

population["London"] = 7172000 ;

population["Paris"] = 2305000;

...

foreach (DictionaryEntry x in tab) Console.WriteLine("{0} = {1}", x.Key, x.Value);

Hashtable

public class Hashtable : IDictionary, IEnumerable, ISerializable, ICloneable { // System.Collections

public HashTable();

public virtual object Clone();

public virtual bool ContainsKey(object key);

public virtual bool ContainsValue(object value);

}

Ví dụ

Hashable population = new Hashtable();

population["Vienna"] = 1592600;

population["London"] = 7172000;

population["Paris"] = 2305000;

...

foreach (DictionaryEntry x in population) Console.WriteLine("{0} = {1}", x.Key, x.Value);

SortedList

Là mảng và được sắp xếp bởi Key

public class SortedList : IDictionary, IEnumerable, ICloneable { // System.Collections

public SortedList(); // variants exist

//... gleiche Members wie Hashtable; zusätzlich:

public virtual int Capacity { get; set; }

public virtual object GetKey(int i); // returns Key[i]

public virtual object GetByIndex(int i); // returns Value[i]

public virtual void SetByIndex(int i, object value);

public virtual IList GetKeyList();

public virtual IList GetValueList();

public virtual int IndexOfKey(object key);

public virtual int IndexOfValue(object value); // returns index of the first occurrence of value

public virtual void RemoveAt(int i);

}

Ví dụ

SortedList population = new SortedList();

population["Vienna"] = 1592600;

population["London"] = 7172000;

...

foreach (DictionaryEntry x in population) Console.WriteLine("{0} = {1}", x.Key, x.Value);

// in ra các phần tử được sắp xếp theo Key

Stack

public class Stack : ICollection, IEnumerable, ICloneable { // System.Collections

public Stack();

public Stack(int initCapacity);

public virtual int Count { get; }

public virtual void Clear();

public virtual void Push(object x);

public virtual object Pop();

public virtual object Peek();

public virtual bool Contains(object x);

public virtual object Clone();

public virtual IEnumerator GetEnumerator();

public virtual object[] ToArray();

...

}

Ví dụ

Stack s = new Stack();

for (int i = 0; i <= 20; i++) s.Push(i);

while (s.Count > 0) Console.Write("{0} ", (int)s.Pop()); // trả về 20 19 18 17 ... 0

Queue

public class Queue : ICollection, IEnumerable, ICloneable { // System.Collections

public Queue();

public virtual int Count { get; }

public virtual void Clear();

public virtual void Enqueue(object x);

public virtual object Dequeue();

public virtual object Peek();

public virtual bool Contains(object x);

public virtual object Clone();

public virtual IEnumerator GetEnumerator();

public virtual object[] ToArray();

...

}

Ví dụ

Queue q = new Queue();

q.Enqueue("one");

q.Enqueue("two");

q.Enqueue("three");

foreach (string s in q) Console.Write(s + " "); // one two three

// q vẫn đầy

Console.WriteLine();

while (q.Count > 0) Console.Write((string)q.Dequeue() + " "); // one two three

// q rỗng

Stream class

Ví dụ FileStream

using System;

using System.IO;

class Test {

static void Copy(string from, string to, int pos) {

try {

FileStream sin = new FileStream(from, FileMode.Open);

FileStream sout = new FileStream(to, FileMode.Create);

sin.Seek(pos, SeekOrigin.Begin); // di chuyển tới cuối file

int ch = sin.ReadByte();

while (ch >= 0) {

sout.WriteByte((byte)ch);

ch = sin.ReadByte();

}

sin.Close();

sout.Close();

} catch (FileNotFoundException e) {

Console.WriteLine("-- file {0} not found", e.FileName);

}

}

static void Main(string[] arg) {

Copy(arg[0], arg[1], 10);

}

}

Bạn đang đọc truyện trên: Truyen2U.Pro

#chương