Tải bản đầy đủ (.pptx) (23 trang)

Delegates, events, lambda expressions trong C#

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (74.52 KB, 23 trang )

Delegates, Events and
Lambda Expressions
Ủy quyền, Sự kiện và biểu thức Lambda
Kiểu delegate

Kiểu delegate là 1 kiểu chứa tham chiếu đến 1 hoặc nhiều phương
thức, đó có thể là phương thức của class hoặc phương thức của
đối tượng. Delegate gần giống với con trỏ hàm trong C/C++

Kiểu delegate thực chất là 1 class kế thừa từ class
System.MulticastDelegate

Delegate cho phép truyền một hàm dưới dạng tham số của hàm
khác
Định nghĩa
kiểu delegate

Định nghĩa kiểu delegate bằng cách dùng từ khóa delegate đi với
kiểu dữ liệu trả về, tên kiểu delegate, danh sách tham số
public delegate double Function(double x)

Để một delegate tham chiếu được đến một phương thức thì cả
delegate phải có chung nguyên mẫu (tức là chung kiểu trả về và
danh sách tham số)
Ví dụ đơn giản
về delegate
public class SimpleMath
{
public delegate int Func(int x, int y);
public static int Add(int x, int y)
{ return x + y; }


public static int Subtract(int x, int y)
{ return x – y; }
static void Main(string[] args)
{
int a = 5, b = 3, c;
Func f = Add;
c = f(a, b); // c = a+b = 8
f = Subtract;
c = f(a, b); // c = a-b = 2
}
}
Một vài thành
viên của kiểu
delegate

Method (MethodInfo): trả về đối tượng mô tả phương thức hiện
tại đối tượng delegate đang chứa

Target (object): trả về đối tượng mà phương thức của nó đang
được đối tượng delegate chứa. Trả về null nếu là phương thức
tĩnh

GetInvocationList() (Delegate[]): trả về 1 mảng chứa các phương
thức hiện có trong đối tượng delegate

Remove hàm tĩnh, trả về 1 delegate sau khi xóa 1 phương thức
public static Delegate Remove(Delegate source,
Delegate value)
Action<T> và
Func<T>

delegate

Đây là các delegate được định nghĩa sẵn, dạng tổng quát của
Action<T> là Action<T1, T2, …>, với T là các kiểu dữ liệu, tối đa là
16 kiểu, tối thiểu là 0. Nguyên mẫu delegate:
delegate void Action<T1, T2, …>(T1 obj1, T2 obj2,
…)

Dạng tổng quát của Func<T> là Func<T1, T2, …, TResult>, tương
tự như Action<T> nhưng có thêm kiểu dữ liệu trả về ở cuối cùng
delegate TResult Func<T1, T2, …, TResult>(T1 obj1,
T2 obj2, …)
Gửi thông báo
thay đổi trạng
thái của
đối tượng
bằng delegate

Ý tưởng: Mỗi khi đối tượng thay đổi trạng thái, ta sẽ gọi hàm xử lí
sự thay đổi trạng thái đó. Hàm này sẽ được truyền vào đối tượng
thông qua 1 đối tượng delegate

Ví dụ sau đây sẽ viết về 1 đối tượng xe, mỗi khi xe thay đổi vận tốc,
nó sẽ thông báo về vận tốc hiện tại của nó
Gửi thông báo
thay đổi trạng
thái của
đối tượng
bằng delegate
class Car

{
private int vantoc;
public int VanToc
{
get { return vantoc; }
set
{
vantoc = value;
if (thaydoi != null)
thaydoi(String.Format("Van toc hien tai la {0} km/h", vantoc));
}
}
private Action<string> thaydoi;
public void TruyenHamXuLi(Action<string> ham)
{
thaydoi = ham;
}
}
Gửi thông báo
thay đổi trạng
thái của
đối tượng
bằng delegate
// Hàm main
static void Main(string[] args)
{
Car a = new Car();
a.TruyenHamXuLi(Console.WriteLine);
for (int i = 0; i < 5; i++)
{

a.VanToc = 10 * i;
}
}
Multicast
delegates

Ta có thể gán nhiều phương thức cho 1 đối tượng delegate, khi gọi đối tượng này, các phương
thức sẽ lần lượt được thực thi theo thứ tự từ cũ đến mới
public class SimpleMath2
{
public static void Add(int x, int y)
{ Console.WriteLine(x + y); }
public static void Subtract(int x, int y)
{ Console.WriteLine(x - y); }
static void Main(string[] args)
{
int a = 5, b = 3, c;
Action<int, int> f = Add;
f += Subtract;
f(a,b);
}
}
Multicast
delegates

Bằng các sử dụng multicast delegate, ta có thể thêm hoặc xóa các
hàm xử lí khi xe thay đổi vận tốc. Ở class Car bên trên, ta thay hàm
TruyenHamXuLi bằng 2 hàm thêm và xóa như ở dưới
public void ThemHamXuLi(Action<string> ham)
{

thaydoi += ham;
}
public void XoaHamXuLi(Action<string> ham)
{
thaydoi -= ham;
}
Multicast
delegates
static void Main(string[] args)
{
Car a = new Car();
a.ThemHamXuLi(Console.WriteLine);
for (int i = 0; i < 3; i++)
{
a.VanToc = 10 * i;
}
a.XoaHamXuLi(Console.WriteLine);
for (int i = 3; i < 5; i++)
{
a.VanToc = 10 * i;
}
}
Events

Event là cách mà 1 class có thể đưa ra các thông báo cho các class
khác khi có 1 sự kiện nào đó xảy ra với nó. Ví dụ như thông báo
thay đổi vận tốc của đối tượng Car như bên trên

Ta có thể tạo 1 sự kiện như ví dụ bên trên bằng cách tạo 1 đối
tượng delegate có mức truy cập private và tạo các hàm để thêm

và bớt các phương thức xử lí

Với từ khóa event, ta có thể rút ngắn quá trình khai báo 1 event chỉ
trong 1 dòng
Events
class Car
{
private int vantoc;
public int VanToc
{
get { return vantoc; }
set
{
vantoc = value;
if (ThayDoi != null)
ThayDoi(String.Format("Van toc hien tai la {0} km/h",
vantoc));
}
}
public event Action<string> ThayDoi;
}
Events
static void Main(string[] args)
{
Car a = new Car();
a.ThayDoi += Console.WriteLine;
for (int i = 0; i < 3; i++)
{
a.VanToc = 10 * i;
}

}
Kết quả:
Van toc hien tai la 0 km/h
Van toc hien tai la 10 km/h
Van toc hien tai la 20 km/h
Delegate
EventHandler

Theo quy ước của .NET, các event chuẩn phải tạo ra từ delegate
EventHandler:
public delegate void EventHandler(
object sender,
EventArgs e
);

Delegate này không trả về giá trị nào, có 2 đối số:

sender: đối tượng tạo ra event

e: đối tượng mô tả các thông tin về event

Ta có thể tạo ra class dẫn xuất từ class EventArgs để chứa thông
tin về event
Custom Event
Argument
class CarEventArgs
{
public readonly string msg;
public CarEventArgs(string message)
{

msg = message;
}
}
Custom Event
Argument
class Car
{
private int vantoc;
public int VanToc
{
get { return vantoc; }
set
{
vantoc = value;
if (ThayDoi != null)
ThayDoi(this, new CarEventArgs (String.Format("Van toc hien tai la
{0} km/h", vantoc)));
}
}
public delegate void CarEventHandler(object sender, CarEventArgs e);
public event CarEventHandler ThayDoi;
}
Custom Event
Argument
static void Main(string[] args)
{
Car a = new Car();
a.ThayDoi += a_ThayDoi;
for (int i = 0; i < 10; i++)
{

a.VanToc = 10 * i;
}
}
static void a_ThayDoi(object sender, CarEventArgs e)
{
Console.WriteLine(e.msg);
}
Delegate
EventHandler<T>

Là 1 kiểu delegate tổng quát với T là lớp dẫn xuất từ lớp EventArgs

Nguyên mẫu:
public delegate void EventHandler<TEventArgs>(
Object sender,
TEventArgs e
)

Cho phép ta không cần phải tạo ra các delegate mới cho các event
Delegate
EventHandler<T>

Thay vì đoạn code
public delegate void CarEventHandler(object sender,
CarEventArgs e);
public event CarEventHandler ThayDoi;

Ta có thể viết gọn lại như sau:
public event EventHandler<CarEventArgs> ThayDoi;
Phương thức

ẩn danh
(Anonymous
Method)

Phương thức ẩn danh cho phép ta khai báo nhanh 1 phương thức để
thêm vào 1 event
a.ThayDoi += delegate(object sender, CarEventArgs e)
{
Console.WriteLine(e.msg);
};
Biểu thức
Lambda
(Lambda
Expression)

Với phương thức ẩn danh, ta đã thu gọn lại khá nhiều các thao tác,
nhưng C# còn cho phép ta rút gọn hơn nữa với biểu thức Lambda

Cú pháp: danh sách tham số => đoạn lệnh của phương thức
a.ThayDoi += (sender, e) => Console.WriteLine(e.msg);
a.ThayDoi += (sender, e) =>
{
Console.WriteLine("Xe thay doi van toc");
Console.WriteLine(e.msg);
};

×