|
|
|
Delegate
เครื่องมือของ.net framework ที่สำคัญอย่างหนึ่งก็คือ delegate ซึ่งแปลตรงตัวก็คือ 'ตัวแทน' โดยการทำงานของมันก็ทำหน้าที่เป็นตัวแทนของ method ต่างๆนั่นเอง
![]() |
รูปด้านบนแสดงลักษณะการใช้งาน Delegate ซึ่งโดยปกติการเรียกใช้ method นั้นเราต้องระบุชื่อ method ที่เราต้องการใช้งาน แต่แนวคิดในการโปรแกรมแบบ Delegate นั้นต่างออกไป โดยแทนที่เราจะเรียกไปที่ methodที่เราต้องการ ตรงๆแต่กลับเรียกผ่าน Delegate แทน ซึ่ง Delegate ก็คือตัวแทน method ที่เราต้องการนั่นเอง โดยผู้เรียก delegate จะไม่รับรู้ว่า method จริงอยู่ที่ส่วนใดของโปรแกรม แค่คิดว่าถ้าเรียกผ่าน Delegate แล้ว Delegate จะต้องมีหน้าที่ทำงานได้ตามที่ผู้เรียกต้องการเท่านั้น
note ลักษณะการใช้งาน Delegate จะเหมือนกับ interface ที่แยก specificaton ออก จาก implementation มักใช้กับ callback function
ในเชิงการเขียนโปรแกรมนั้น Delegate คือ class ที่มี reference ไปยัง method ที่มี signature ตรงตามคุณสมบัติของ Delegate ตัวนั้น พูดได้ว่า Delegate ก็คือ pointer to function ของ C++ ในแบบฉบับที่เป็น object-oriented นั่นเอง
เรามาลองสำรวจรายละเอียดของ Delegate กันก่อน โดยเริ่มจากการประกาศ Delegate ขึ้นมาตัวหนึ่ง
|
จุดประสงค์ของประโยคด้านบนคือ ประกาศDelegate type ชื่อ Mydelegate ซึ่งไม่มี argument และมี return type เป็น void
เบื้องหลังการทำงานนั้น compiler จะสร้าง metadata และ class ที่สืบทอดมาจาก MulticastDelegatให้อย่างอัตโนมัติ ซึ่งสามารถแสดงดัง psuedocode ต่อไปนี้
//psuedo code
class Mydelegate : MulticastDelegate
{
public Mydelegate(object obj, int ptr)
{ }
public void Invoke()
{ }
}
|
ซึ่งส่วน implementation ของ constructor และ invoke จะไม่เห็นรายละเอียดเพราะcode ส่วนนี้จะสร้างโดยจัดการโดย CLR อย่างอัตโนมัติ
เรามาดูชัดๆอีกทีว่า class Mydelegateของเราทีหน้าตาอย่างไร ซึ่งแสดงได้ตาม class digram ด้านล่าง
![]() |
ต่อไปเรามาดูในส่วน asssembly กันบ้าง โดยใช้โปรแกรม ILDASM.EXE
![]() |
จะเห็นว่า class Mydelegate นั้นเป็นไปตามที่ class digram ได้อธิบายไว้คือ inherit มาจาก class MulticastDelegate ซึ่งอันที่จริงแล้วหนทางที่จะ inherit MulticastDelegate class นั้นมีวิธีเดียวคือต้องประกาศ Delegate typeเท่านั้น
note compiler ยังสร้างอีก 2 method คือ BeginInvoke() and EndInvoke() ซึ่งใช้ในการเขียนโปรแกรมแบบ asynchronus ซึ่งจะไม่พูดถึงในบทความนี้ครับ
ขั้นต่อไปก็คือการเรียกใช้งาน โดยมี2ขั้นตอนคือ
1. ประกาศ instance ของ Delegate โดยมี constructor arguments เป็น
Mydelegate(object obj, int ptr)
arguments obj และ ptr นั้นมีไว้สำหรับ bind method เข้ากับ delegate ของเรา ซึ่งการ bind method เข้ากับ delegate นั้น มี 2 แบบ คือ
|
- static method
- instance method
|
แต่ C# syntax นั้นช่วยให้การ bind method เข้ากับ Delegate instance นั้นง่ายขึ้น โดย syntax สนับสนุนการ bind method โดยใช้ argument เพียวตัวเดียวเท่านั้น ดังต่อไปนี้
static method
delegate void Mydelegate ();
class Class1
{
static void fnc()
{
//some code
}
static void Main(string[] args)
{
//some code
Mydelegate m = new Mydelegate (Class1.fnc);
//some code
}
}
|
instance method
delegate void Mydelegate ();
class Class1
{
public void fnc ()
{
//some code
}
static void Main (string[] args)
{
//some code
Class1 c = new Class1();
Mydelegate m = new Mydelegate (c.fnc);
//some code
}
}
|
C# compiler จะนำชื่อ method
ที่เราใส่เข้าไป นำไปตรวจสอบ กับ code ของเรา แล้วจากนั้นจึงแปลงเป็นการ bind แบบปกติให้อย่างอัตโนมัติ
2. เรียกใช้งาน method โดยเรียกผ่าน method Invoke ของ class Mydelegateแต่
syntax ของ C# นั้นไม่อนุญาติให้เรียก Invoke ได้ตรงๆแต่ให้เรียกด้วย syntax ลักษณะดังนี้
Mydelegate m = new Mydelegate (c.fnc);
m(); // m.Invoke()
ซึ่ง compiler ก็ generate code ที่เรียกใช้ method Invoke() นั่นเอง สังเกตจาก MSIL

Delegate type ที่ inherit มาจาก Delegate (MulticastDelegate เป็น derived class ของ Delegate) จะมี invocation list ซึ่งเป็น link list ของ delegate ที่จะถูกเรียกตามลำดับเมื่อเรียก method Invoke ของ delegate
code ตัวอย่างที่ผ่านมาทางด้านบนนั้นเป็นลักษณะของ single-cast delegate นั่นคือใน invocation list มี delegate เพียง 1 ตัว ซึ่งเราสามารถสร้าง multi-cast delegate ได้ โดยใช้ method Combine ใน class Delegate เพิ่ม delegate เข้าไปใน invocation list
ในทางกลับกัน เราก็สามารถลบ delegate ออกจาก invocation list ได้โดย method Remove ของ class Delegate| delegate
void
Mydelegate (); class Class1 { public static void fnc() { Console.WriteLine("Hello"); } static void Main(string[] args) { //some code Mydelegate m = new Mydelegate (Class1.fnc); Mydelegate n = new Mydelegate (Class1.fnc); m = (Mydelegate)Delegate.Combine(m,n); m(); // Invoke() //result is /* Hello Hello */ m = (Mydelegate)Delegate.Remove(m,n); m(); // Invoke() //result is /* Hello */ //some code } } |
C# syntax ช่วยให้การใช้งาน multi-cast delegate ง่ายขึ้นโดยแทนที่จะเรียกใช้ Combine, Remove ก็มีอีก 1 ทางเลือกคือ ใช้ operator += และ -=
จาก code ตัวอย่างด้านบนเราสามารถเขียนแบบ operator += , -= ได้ดังนี้
class Class1 { public static void fnc() { Console.WriteLine("Hello"); } static void Main(string[] args) { //some code Mydelegate m = new Mydelegate (Class1.fnc); Mydelegate n = new Mydelegate (Class1.fnc); m += n; m(); // Invoke() m -= n; m(); // Invoke() //some code } } |
code ในลักษณะนี้ compiler จะแปลงไปอยู่ในรูปแบบ Combine และ Remove โดยอัตโนมัติ สังเกตได้จาก MSIL
สรุป
บทความนี้ได้พูดถึงการใช้งาน Delegate ซึ่งประกอบไปด้วยหัวข้อ การประกาศ delegate type,การ bind method,การเรียกใช้งาน delegate,การสร้างและใช้งาน single-cast, multi-cast delegate
delegate เป็นกลไกที่สำคัญใน .net framework ซึ่งบทความนี้ก็ได้กล่าวถึงรายละเอียดการทำงานของ delegat พอสมควร ซึ่งการทำความเข้าใจกลไกก็จะช่วยให้เราสามารถเขียนโปรแกรมที่ดีขึ้นได้ครับ
บทความตอนต่อจาก delegate ก็คงจะเป็น event ซึ่งมีพื้นฐานมาจาก delegate นั่นเองครับ
ปรับปรุงครั้งล่าสุด 12/11/2544