Kiểu delegate
• Windows API sử dụng con trỏ hàm để hỗ trợ cơ chế gọi ngược
(callback mechanism)
• Một hàm gọi lại một hàm khác
• Có thể xử lý các sự kiện nhấn chuột, di chuyển chuột,
• Trong .NET, delegate là một đối tượng an toàn kiểu, tham
chiếu đến một hàm khác (hoặc danh sách các hàm) mà có thể
được triệu gọi khi cần thiết
• 3 bước sử dụng delegate:
• Định nghĩa
• Tạo đối tượng kiểu delegate, đăng ký hàm xử lý
• Triệu gọi
28 trang |
Chia sẻ: thanhle95 | Lượt xem: 512 | Lượt tải: 1
Bạn đang xem trước 20 trang tài liệu Bài giảng Lạp trình hướng đối tượng - Chương 7: Uỷ thác và sự kiện - Lê Viết Mẫn, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
v 1.0 - 11/2018
Uỷ thác và sự kiện
1
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Nội dung
2
1. Uỷ thác
2. Sự kiện
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Uỷ thác
Delegate
3
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Cơ chế Uỷ thác
• Muốn thực thi một phương thức nào đó của một đối tượng nào
đó nhưng người lập trình có thể chưa rõ lúc thiết kế
• Dịch vụ gọi báo thức
• Lúc 2h sáng, gọi số điện thoại 0905xxxxxx để tôi dậy coi đá banh
• Một Button Control trong lập trình Windows Form
• Khi nút được nhấn, gọi hàm Click của Form để hiển thị chữ “Hello World” lên màn hình
• Ví dụ: https://youtu.be/Vw05kQhh4tY?t=1773
• Gồm 3 phần:
• Hàm sẽ được gọi
• Việc hàm đó sẽ làm
• Sự kiện
• Uỷ thác là cơ chế tạo ra các kiểu dữ liệu cho phép lưu giữ các
hàm sẽ được gọi
4
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Kiểu delegate
• Windows API sử dụng con trỏ hàm để hỗ trợ cơ chế gọi ngược
(callback mechanism)
• Một hàm gọi lại một hàm khác
• Có thể xử lý các sự kiện nhấn chuột, di chuyển chuột,
• Trong .NET, delegate là một đối tượng an toàn kiểu, tham
chiếu đến một hàm khác (hoặc danh sách các hàm) mà có thể
được triệu gọi khi cần thiết
• 3 bước sử dụng delegate:
• Định nghĩa
• Tạo đối tượng kiểu delegate, đăng ký hàm xử lý
• Triệu gọi
5
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Định nghĩa
• Cú pháp khai báo nguyên mẫu hàm kèm với từ khoá delegate
• delegate phải giống với nguyên mẫu hàm của các hàm mà nó sẽ trỏ tới
• Kiểu delegate trên có thể trỏ đến bất kỳ hàm nào nhận vào 2 số nguyên và
trả ra một số nguyên
• .NET tự động tạo ra một lớp có tên là tên của delegate, và có
3 hàm: Invoke, BeginInvoke và EndInvoke
6
public delegate int BinaryOp(int x, int y);
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Tạo đối tượng và triệu gọi
7
static int Add(int x, int y)
{
return x + y;
}
static int Subtract(int x, int y)
{
return x - y;
}
BinaryOp b = new BinaryOp(Add); // tạo đối tượng, đăng ký hàm
// triệu gọi, như gọi hàm
Console.WriteLine("10 + 10 is {0}", b(10, 10));M
ai
n(
)
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Đăng ký và huỷ đăng ký
• Sử dụng toán tử += để đăng ký hàm xử lý
• Biến kiểu delegate có thể nhận nhiều hàm xử lý
• Sử dụng toán tử -= để huỷ đăng ký
8
// Danh sách chứa các hàm xử lý
BinaryOp listOfHandlers;
listOfHandlers += Add;
listOfHandlers += Subtract;
listOfHandlers -= Add;
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Ví dụ - giám sát sự thay đổi dữ liệu
• Viết hai lớp:
• PointController - giám sát sự thay đổi dữ liệu của lớp Point. Nếu có thay
đổi thì làm gì đó (ví dụ: in thông báo sự thay đổi)
• Point - gửi thông báo (triệu gọi hàm) cho lớp PointController (hoặc các
lớp khác nếu có đăng ký) thông qua kiểu delegate
• Lớp Point có:
• Định nghĩa kiểu delegate mới
• Khai báo biến thành phần kiểu delegate đó
• Tạo hàm trợ giúp để cho phép các lớp, muốn giám sát sự thay đổi dữ liệu của
lớp Point, có thể đăng ký
• Tại những nơi có sự thay đổi dữ liệu, triệu gọi các hàm của các lớp đã đăng ký
9
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Ví dụ - giám sát sự thay đổi dữ liệu
• Lớp PointController có:
• Hàm xử lý khi có sự thay đổi dữ liệu, có nguyên mẫu hàm phù hợp với kiểu
delegate của lớp Point
• Đăng ký hàm trên với lớp Point
10
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp Point
11
class Point
{
int x;
public int X
int y;
public int Y
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
// Khai báo kiểu delegate
public delegate void ChangedValueHandler(int newX, int newY);
// Danh sách chứa các hàm xử lý
private ChangedValueHandler listOfHandlers;
// Nơi đăng ký nhận hàm xử lý
public void RegisterWithChangedValue(ChangedValueHandler methodToCall)
{
listOfHandlers += methodToCall;
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp Point
12
class Point
{
int x;
public int X
{
get { return x; }
set
{
x = value;
if (listOfHandlers != null)
listOfHandlers.Invoke(value, y); // Gọi hàm xử lý
}
}
int y;
public int Y
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp PointController
13
class PointController
{
Point p;
public PointController(Point p)
{
this.p = p;
// Đăng ký hàm xử lý
this.p.RegisterWithChangedValue(ChangedValueEvent);
}
// Hàm xử lý
public static void ChangedValueEvent(int newX, int newY)
{
Console.WriteLine("{0}-{1}", newX, newY);
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp Program
14
class Program
{
static void Main(string[] args)
{
Point p = new Point(0, 0);
PointController pc = new PointController(p);
p.X = 1;
p.Y = 1;
Console.ReadKey();
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Sự kiện
Event
15
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Sự kiện
• Ứng với mỗi thao tác người dùng sẽ có một sự kiện phát sinh,
chương trình phải đáp ứng cho mỗi sự kiện này
• Dịch vụ gọi báo thức
• Lúc 2h sáng, gọi số điện thoại 0905xxxxxx để tôi dậy coi đá banh
• Một Button Control trong lập trình Windows Form
• Khi nút được nhấn, gọi hàm Click của Form để hiển thị chữ “Hello World” lên màn hình
• Sử dụng cơ chế Uỷ thác để cài đặt
• Một kiểu dữ liệu đặc biệt của delegate
• Khái niệm Publishing và Subcribing
• Publishing - một lớp phát sinh sự kiện
• Subscribing - các lớp đăng ký sẽ nhận thông báo về sự kiện phát sinh và
thực thi gì đó để đáp ứng với sự kiện
16
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Ba bước sử dụng event
1. Định nghĩa event
2. Đăng ký, huỷ đăng ký
3. Gửi thông báo sự kiện xảy ra
17
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Định nghĩa event
• Hai bước:
• Khi khai báo biến kiểu delegate có kèm từ khoá event, trình
biên dịch sẽ tự động cung cấp:
• Các hàm đăng ký và huỷ đăng ký
• Các biến thành phần kiểu delegate trên (luôn là private)
• Làm đơn giản đi quá trình truyền thông báo cho các đối tượng
ngoài
18
// Vẫn khai báo kiểu delegate
public delegate void ChangedValueHandler(int newX, int newY);
// Vẫn khai báo biến event kiểu delegate trên
public event ChangedValueHandler ChangedValueEvent;
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Đăng ký và huỷ đăng ký
• Sử dụng toán tử += để đăng ký
• Sử dụng toán tử -= để huỷ đăng ký
19
static void ChangedValue(int newX, int newY)
{
Console.WriteLine("{0}-{1}", newX, newY);
}
ChangedValueEvent += ChangedValue;
ChangedValueEvent -= ChangedValue;
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Gửi thông báo event
• Giống như gọi hàm
20
class Point
{
int x;
public int X
{
get { return x; }
set
{
x = value;
if (ChangedValueEvent != null)
ChangedValueEvent.Invoke(value, y);
}
}
}
ChangedValueEvent(value, y);
hoặc
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Ví dụ - giám sát sự thay đổi dữ liệu
• Lớp Point có:
• Định nghĩa kiểu delegate mới
• Định nghĩa event mới thuộc kiểu delegate trên
• Tại những nơi có sự thay đổi dữ liệu, gửi thông báo bằng cách gọi event và
truyền các tham số cần thiết
• Lớp PointController có:
• Hàm xử lý khi có sự thay đổi dữ liệu, có nguyên mẫu hàm phù hợp với kiểu
delegate của lớp Point
• Đăng ký hàm trên với lớp Point
21
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp Point
22
class Point
{
int x;
public int X
{
get { return x; }
set
{
x = value;
if (ChangedValueEvent != null)
ChangedValueEvent(value, y); // truyền thông báo
}
}
int y;
public int Y
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
// Kiểu sự kiện
public delegate void ChangedValueHandler(int newX, int newY);
public event ChangedValueHandler ChangedValueEvent;
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp PointController
23
class PointController
{
Point p;
public PointController(Point p)
{
this.p = p;
p.ChangedValueEvent += ChangedValueEvent;
}
~PointController()
{
p.ChangedValueEvent -= ChangedValueEvent;
}
// Hàm xử lý sự kiện
public static void ChangedValueEvent(int newX, int newY)
{
Console.WriteLine("{0}-{1}", newX, newY);
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Lớp Program
24
class Program
{
static void Main(string[] args)
{
Point p = new Point(0, 0);
PointController pc = new PointController(p);
p.X = 1;
p.Y = 1;
Console.ReadKey();
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Sử dụng toán tử kiểm tra null
• Sử dụng toán tử kiểm tra null
25
public int X
{
get { return x; }
set
{
x = value;
// kiểm tra khác null trước khi truyền thông báo
if (ChangedValueEvent != null)
ChangedValueEvent(value, y); // truyền thông báo
}
}
public int X
{
get { return x; }
set
{
x = value;
ChangedValueEvent?.Invoke(value, y);
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Tuỳ biến đối số dòng lệnh của event
• Khi gửi thông báo, các tham số cần truyền là vấn đề lớn cần xử
lý
• Theo mẫu thiết kế sự kiện (event pattern) của Microsoft, nên:
• Tạo lớp mới, thừa kế từ lớp System.EventArgs
• Lớp này gói tất cả các tham số cần truyền lại
26
class PointEventArgs : System.EventArgs
{
public readonly int X;
public readonly int Y;
public PointEventArgs(int x, int y)
{
this.X = x;
this.Y = x;
}
}
Lê Viết Mẫn - lvman@hce.edu.vn Uỷ thác và sự kiện
Những thay đổi
• Định nghĩa event
• Gửi thông báo sự kiện xảy ra
27
// Khai báo kiểu delegate
public delegate void ChangedValueHandler
(object sender, PointEventArgs e);
// Khai báo biến event kiểu delegate trên
public event ChangedValueHandler ChangedValueEvent;
ChangedValueEvent(this, new PointEventArgs(x, y));
Lê Viết Mẫn - lvman@hce.edu.vn
Cảm ơn sự chú ý
Câu hỏi ?
Uỷ thác và sự kiện 28