Free Web Hosting by Netfirms
Web Hosting by Netfirms | Free Domain Names by Netfirms

  
 

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 void Mydelegate ();

      จุดประสงค์ของประโยคด้านบนคือ ประกาศ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

obj เป็น null

ptr เป็น address ของ method ที่จะ bind

     - instance method

obj เป็น reference ของ instance ที่จะ bind method

ptr เป็น address ของ method ที่จะ bind

      แต่ 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 += , -= ได้ดังนี้

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
+= 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