Delegate và Event Gvhd: Nguyn Tn Trn Minh Khang
87
Chương 12 Delegate và Event
Delegate có nghĩa là y quyn hay y thác. Trong lp trình đôi lúc ta gp tình hung
phi thc thi mt hành động nào đó, nhưng li không biết s gi phương thc nào
ca đối tượng nào. Chng hn, mt nút nhn button khi được nhn phi thông báo
cho đối tượng nào đó biết, nhưng đối tượng này không th được tiên đoán trong lúc
cài đặt lp button. Vì vy ta s kết ni lp button vi mt đối tượng y thác và y
thác (hay thông báo) cho đối tượng này trách nhim thc thi khi button được nhn.
Đối tượng y thác s được gán (đăng ký y thác) vào thi đim khác thích hp.
Event có nghĩa là s kin. Ngày nay mô hình lp trình giao din người dùng đồ ha
(Graphical User Interface - GUI) đòi hi cách tiếp cn theo hướng s kin. Mt ng
dng ngày nay hin th giao din người dùng và ch người dùng thao tác. ng vi
mi thao tác như chn mt trình đơn, nhn mt nút button, nhp liu vào ô textbox
… s mt s kin s phát sinh. Mt s kin có nghĩa là có điu gì đó đã xy ra và
chương trình phi đáp tr.
Delegate và event là hai khái nim có liên quan cht ch vi nhau. Bi vì để qun lý
các s kin mt cách mm do đòi hi các đáp tr phi được phân phi đến các
trình gii quyết s kin. Trình gii quyết s kin trong C# được cài đặt bng
delegate.
Delegate còn được s dng như mt hàm callback. Hàm callback là hàm có th
được t động gi bi hàm khác. Công dng th hai này ca delegate được đề cp
trong chương 19.
12.1 Delegate (y thác, y quyn)
Trong C#, delegate được h tr hoàn toàn bi ngôn ng. V mt k thut,
delegate thuc kiu tham chiếu được dùng để đóng gói phương thc đã xác định
kiu tr v và s lượng, kiu tham s. Chúng ta có th đóng gói bt k phương thc
thc nào phù hp vi phương thc ca delegate. (Trong C++ có k thut tương
t là con tr hàm, tuy nhiên delegate có tính hướng đối tượng và an toàn v kiu)
Mt delegate có th được to bng t khóa delagate, sau đó là kiu tr v, tên
delegate và các tham s ca phương thc mà delegate chp nhn:
public delegate int WhichIsFirst(object obj1, object obj2)
Dòng trên khai báo mt delegate tên là WhichIsFirst có th đóng gói (nhn)
bt k mt phương thc nào nhn vào hai tham s kiu object và tr v kiu int.
Delegate và Event Gvhd: Nguyn Tn Trn Minh Khang
88
Khi mt delegate được định nghĩa, ta có th đóng gói mt phương thc vi
delegate đó bng cách khi to vi tham s là phương thc cho delegate.
12.1.1 Dùng delegate để xác định phương thc vào lúc chy
Delegate được dùng để xác định (specify) loi (hay kiu) ca các phương thc dùng
để qun lý các s kin; hoc để cài đặt các hàm callback trong ng dng. Chúng
cũng được dùng để xác định các phương thc tĩnh và không tĩnh (còn gi là phương
thc th hin - instance methods: là phương ch gi được thông qua mt th hin
ca lp) chưa biết trước vào lúc thiết kế (có nghĩa là ch biết vào lúc chy).
Ví d, gi s chúng ta mun to mt lp túi cha đơn gin có tên là Pair (mt
cp). Lp này cha 2 đối tượng được sp xếp. Chúng ta không biết trước được đối
tượng nào s được truyn vào cho mt th hin ca lp Pair, vì vy không th xây
dng hàm sp xếp tt cho tt c các trường hp. Tuy nhiên ta s đẩy trách nhim
này cho đối tượng bng cách to phương thc mà công vic sp xếp có th y thác.
Nh đó ta có th sp th th ca các đối tượng chưa biết bng cách y thác trách
nhim này chính phương thc ca chúng.
Ta định nghĩa mt delegate có tên WhichIsFirst trong lp Pair. Phương thc
sort s nhn mt tham s kiu WhichIsFirst. Khi lp Pair cn biết th t ca
đối tượng bên trong, nó s gi delegate vi hai đối tượng làm tham s. Trách nhim
quyết định xem đối tượng nào trong 2 đối tượng có th t trước được y thác cho
phương thc được đóng gói trong delegate.
Để kim th delegate, ta to ra hai lp: DogStudent. Lp DogStudent
không ging nhau ngoi tr c hai cùng cài đặt phương thc có th được đóng gói
bi WhichIsFirst, vì vy c Dog ln Student đều thích hp được gi trong đối
tượng Pair.
Để kim th chương trình chúng ta to ra mt cp đối tượng Student và mt cp
đối tương Dog và lưu tr chúng trong hai đối tượng Pair. Ta s to mt đối tượng
delegate để đóng gói cho tng phương thc, sau đó ta yêu cu đối tượng Pair
sp xếp đối tượng DogStudent. Sau đây là các bước thc hin:
public class Pair
{
// cp đối tượng
public Pair(object firstObject, object secondObject)
{
thePair[0] = firstObject;
thePair[1] = secondObject;
}
// biến lưu gi hai đối tượng
private object[]thePair = new object[2];
Kế tiếp, ta override hàm ToString()
public override string ToString( )
{
return thePair[0].ToString() + ", " + thePair[1].ToString();
Delegate và Event Gvhd: Nguyn Tn Trn Minh Khang
89
}
Chúng ta đã có hai đối tượng trong lp Pair và có th in chúng ra. Bây gi là phn
sp xếp chúng và in kết qu sp xếp. Chúng ta không th biết trước s có loi đối
tượng nào, và vì vy chúng ta s y thác quyn quyết định đối tượng nào có th t
trước cho chính các đối tượng. Như vy ta s yêu cu đối tượng được xếp th t
trong lp Pair phi cài đặt phương thc cho biết trong hai đối tượng, đối tượng nào
có th t trước. Phương thc này s nhn vào hai đối tượng (thuc bt k loi nào)
và tr v kiu lit kê: theFirstComeFirst nếu đối tượng đầu có th t trước và
theSecondComeFirst nếu đối tượng sau có th t trước.
Nhng phương thc này s được đóng gói bi delegate WhichIsFirst định
nghĩa trong lp Pair.
public delegate comparisn WhichIsFirst(object obj1,object obj2)
Tr tr v thuc kiu kiu lit kê comparison.
public enum comparison
{
theFirstComesFirst = 1,
theSecondComesFirst = 2
}
Bt k mt phương thc tĩnh nào nhn hai tham s kiu object tr v kiu
comparison đều có th được đóng gói bi delegate này vào lúc chy.
Bây gi ta định nghĩa phương thc Sort ca lp Pair
public void Sort(WhichIsFirst theDelegatedFunc)
{
if ( theDelegatedFunc(thePair[0],thePair[1]) ==
comparison.theSecondComesFirst )
{
object temp = thePair[0];
thePair[0] = thePair[1];
thePair[1] = temp;
}
}
Phương thc này nhn mt tham s delegate tên WhichIsFirst. Phương thc
Sort y thác quyn quyết định đối tượng nào có th t trước cho phương thc
được đóng gói trong delegate. Trong thân hàm Sort(), có li gi phương thc
được y thác và xác định giá tr tr v.
Nếu tr tr vtheSecondComesFirst, hai đối tượng trong Pair s hoán
chuyn v trí, ngược li không có gì xy ra.
Chúng ta s xp xếp các sinh viên theo th t tên. Chúng ta phi viết mt phương
thc tr v theFirstComesFirst nếu tên ca sinh viên đầu có th t trước và
ngược li theSecondComesFirst nếu tên sinh viên sau có th t trước. Nếu hàm
tr v theSecondComesFirst ta s thc hin vic đảo v trí ca hai sinh viên
trong Pair.
Delegate và Event Gvhd: Nguyn Tn Trn Minh Khang
90
Bây gi thêm phương thc ReverseSort, để sp các đối tượng theo th t ngược.
public void ReverseSort(WhichIsFirst theDelegatedFunc)
{
if ( theDelegatedFunc(thePair[0], thePair[1]) ==
comparison.theFirstComesFirst )
{
object temp = thePair[0];
thePair[0] = thePair[1];
thePair[1] = temp;
}
}
Bây gi chúng ta cn vài đối tượng để sp xếp. Ta s to hai lp StudentDog.
Gán tên cho Student lúc khi to
public class Student
{
public Student(string name)
{
this.name = name;
}
Lp Student yêu cu hai phương thc, mt override t hàm ToString()
mt để đóng gói như phương thc được y thác.
Student phi override hàm ToString() để phương thc ToString() trong
lp Pair gi. Hàm ch đơn gin tr v tên ca sinh viên.
public override string ToString()
{
return name;
}
Cũng cn phi cài đặt phương thc để Pair.Sort() có th y thác quyn quyết
định th t hai đối tượng.
return (String.Compare(s1.name, s2.name) < 0 ?
comparison.theFirstComesFirst :
comparison.theSecondComesFirst );
Hàm String.Compare là phương thc ca lp String trong thư vin .Net
Framework. Hàm so sánh hai chui và tr v s nh hơn 0 nếu chui đầu nh hơn
và tr v s ln hơn 0 nếu ngược li. Chú ý rng hàm tr v
theFirstComesFirst nếu chui đầu nh hơn, và tr v
theSecondComesFirst nếu chui sau nh hơn.
Lp th hai là Dog. Các đối tượng Dog s được sp xếp theo trng lượng, con nh s
đứng trước con nng. Đây là khai báo đầy đủ lp Dog:
public class Dog
{
public Dog(int weight)
{
this.weight=weight;
}
// dogs are ordered by weight
Delegate và Event Gvhd: Nguyn Tn Trn Minh Khang
91
public static comparison WhichDogComesFirst( Object o1,
Object o2 )
{
Dog d1 = (Dog) o1;
Dog d2 = (Dog) o2;
return d1.weight > d2.weight ? theSecondComesFirst :
theFirstComesFirst;
}
public override string ToString( )
{
return weight.ToString( );
}
private int weight;
}
Chú ý rng lp Dog cũng override phương thc ToString() và cài đặt phương
thc tĩnh vi nguyên mu hàm được khai báo trong delegate. Cũng chú rng hai
phương thc chun b y thác ca hai lp DogStudent không cn phi trùng
tên. Ví d 12 - 1 là chương tình hoàn chnh. Chương trình này gii thích cách các
phương thc y thác được gi.
Ví d 12 - 1. Làm vic vi delegate
using System;
namespace Programming_CSharp
{
public enum comparison
{
theFirstComesFirst = 1,
theSecondComesFirst = 2
}
// túi cha đơn gin cha 2 đối yựơng
public class Pair
{
// khai báo delegate
public delegate comparison WhichIsFirst( object obj1,
object obj2 );
// hàm khi to nhn 2 đối tượng
// ghi nhn theo đúng trình t nhn vào
public Pair( object firstObject, object secondObject)
{
thePair[0] = firstObject;
thePair[1] = secondObject;
}
// phương thc sp th t (tăng) hai đối tượng
// theo th t do chính chúng qui định.
public void Sort(WhichIsFirst theDelegatedFunc)
{
if ( theDelegatedFunc(thePair[0],thePair[1]) ==
comparison.theSecondComesFirst )
{
object temp = thePair[0];
thePair[0] = thePair[1];
thePair[1] = temp;
}
}