Delegates
ในบทนี้ เราจะพูดเกี่ยวกับ Delegates และวิธีการใช้งานกับเมธอดในภาษา C#
Delegates คืออะไร
Delegates เป็นตัวแปรประเภท reference type ที่ถูกพัฒนาขึ้นมาสนับสนุนการเขียนโปรแกรมในภาษา C# มันใช้สำหรับในการอ้างถึงข้อมูลอื่น แทนที่จะอ้างถึงออบเจ็ค มันอ้างถึงเมธอดแทน หรือกล่าวอีกนัยหนึ่ง delegates คือพอยน์เตอร์ของเมธอดนั่นเอง
การใช้ delegates นั้นช่วยอำนวนความสะดวกหลายอย่าง เช่น การเลือกเมธอดที่จะทำงานใน run time การนำกลับมาใช้ใหม่ของโค้ด นอกจากนี้ delegates ยังทำให้สามารถส่งเมธอดเป็นพารามิเตอร์ได้ อย่างไรก็ตามปราศจาก delegates เราก็ยังสามารถเรียกใช้เมธอดแบบปกติได้
การใช้ delegates
ต่อไปเราจะมีตัวอย่างสำหรับการประกาศและใช้งาน delegates ในภาษา C#
using System;
class DelegatesExample
{
delegate void MyDelegates();
static void Main(string[] args)
{
MyDelegates de = new MyDelegates(Callback);
de();
de = Callback2;
de();
}
static void Callback () {
Console.WriteLine("Called by Delegate.");
}
static void Callback2()
{
Console.WriteLine("Second method, called by Delegate.");
}
}
ตัวอย่างข้างบน เราได้ประกาศ delegate type ขึ้นมา โดย delegate นี้จะสามารถทำงานได้กับเมธอดที่มีการส่งค่าลกับเป็น void และไม่มีพารามิเตอร์
delegate void MyDelegates();
ในเมธอด Main()
เราได้สร้างตัวแปร delegate เพื่อทำมาใช้เมธอดประเภทดังกล่าว และใส่พารามิเตอร์เป็น Callback ()
สำหรับ delegate constructor ตอนนี้ตัวแปร delegate de
อ้างถึงเมธอดดังกล่าว และเราเรียกใช้เมธอด
MyDelegates de = new MyDelegates(Callback);
de();
ต่อมาเราได้กำหนดให้ delegate อ้างไปยังเมธอด Callback2()
และเรียกใช้เมธอดอีกครั้ง ในคำสั่ง
de = Callback2;
de();
เพราะว่าเมธอด Callback() และ Callback2() เป็นเมธอดที่มีการส่งกลับเป็น void และไม่มีพารามิเตอร์ ดังนั้นมันจึงสามารถใช้ได้กับ delegate นี้
Called by Delegate.
Second method, called by Delegate.
และนี่เป็นผลลัพธ์ของโปรแกรมในการใช้งานเมธอดกับ delegate
คุณสามารถประกาศ delegate แบบสั้นได้ โดยไม่ต้องใส่เมธอดลงไปใน constructor ซึ่งเป็นอีกวิธีที่จะอำนวยความสะดวกในการเขียนโปรแกรม ยกตัวอย่างเช่น
MyDelegates de = Callback;
Delegates กับพารามิเตอร์และ return
ต่อไปเราจะมาสร้าง delegate กับพารามิเตอร์ เพื่อส่งตัวแปรเข้าไปทำงานในเมธอด เช่นเดียวกันกับเมธอด delegate สามารถส่งค่ากลับ มีประเภทหรือจำนวนของพารามิเตอร์ที่แตกต่างกันได้
using System;
class DelegatesExample2
{
delegate string MyDelegates(string s);
static void Main(string[] args)
{
Person p1 = new Person("Max", "Graham");
MyDelegates de = p1.GreetFirstName;
String name1 = de("Hey");
de = p1.GreetLastName;
String name2 = de("Hi");
Console.WriteLine(name1);
Console.WriteLine(name2);
}
}
class Person {
string firstName;
string lastName;
public Person (string f, string n) {
firstName = f;
lastName = n;
}
public string GreetFirstName (string s) {
return s + " " + firstName;
}
public string GreetLastName(string s) {
return s + " " + lastName;
}
}
เหมือนเมธอด delegate สามารถส่งค่ากลับและมีพารามิเตอร์ ในตัวอย่างเราได้สร้าง delegate ที่มีการส่งค่ากลับเป็น string และมีพารามิเตอร์เป็น string หนึ่งตัว แต่ตอนนี้เราใช้กลับเมธอดของคลาส ในตัวอย่างเราได้ใช้ delegate เรียกใช้เพื่อสร้างประโยคทักทาย ว่าจากชื่อหรือนามสกุล
Hey Max
Hi Graham
และนี่เป็นผลลัพธ์ของโปรแกรม
Multicast delegate
ในการใช้งาน delegate กับเมธอดนั้น เราสามารถเพิ่มเมธอดเข้าไปยัง delegate เพื่อให้มันเรียกหลายๆ ครั้งได้ โดยการใช้ตัวดำเนินการ +=
เป็นการเพิ่มเมธอดใหม่ให้กับ delegate และ -=
เป็นการนำเมธอดออกจาก delegate มาดูตัวอย่าง
using System;
class DelegatesExample3
{
delegate void MyDelegates(int a, int b);
static void Main(string[] args)
{
MyDelegates de;
de = Add;
de += Sub;
de += Mul;
de(5, 3);
de -= Add;
de(10, 8);
}
static void Add(int a, int b)
{
Console.WriteLine(a + " + " + b + " = " + (a + b));
}
static void Sub(int a, int b)
{
Console.WriteLine(a + " - " + b + " = " + (a - b));
}
static void Mul(int a, int b)
{
Console.WriteLine(a + " * " + b + " = " + (a * b));
}
}
ในตัวอย่าง เราได้สร้าง delegate สำหรับใช้งานกับเมธอดที่มีค่าส่งกลับเป็น void และพารามิเตอร์สองตัวที่เป็น int ในตอนแรกเราได้เพิ่ม 3 เมธอดเข้าไปยัง delegate นั่นทำให้เมื่อเราเรียกใช้ delegate ในคำสั่ง de(5, 3);
เมธอดทั้งหมกใน delegate ทำงานจากพารามิเตอร์ที่ส่งเข้าไป
de = Add;
de += Sub;
de += Mul;
de(5, 3);
ต่อมาเรานำเมธอด Add()
ออกจาก delegate แล้วเรียกใช้อีกครั้ง
5 + 3 = 8
5 - 3 = 2
5 * 3 = 15
10 - 8 = 2
10 * 8 = 80
นี่เป็นผลลัพธ์ของโปรแกรม
Delegates เป็นพารามิเตอร์ของเมธอด
นอกจากนี้ ภาษา C# ยังสามารถให้ delegate ส่งเป็นพารามิเตอร์เข้ามายังเมธอดได้ มันอำนวยความสะดวกในการสร้าง callback เมธอด ที่เรียกใช้งานเมธอดโดยชื่อของมัน
using System;
class DelegatesExample4
{
delegate void MyDelegates();
static void Main(string[] args)
{
Callback(Method1);
Callback(Method2);
}
static void Callback (MyDelegates m)
{
m();
}
static void Method1 () {
Console.WriteLine("Call method 1");
}
static void Method2()
{
Console.WriteLine("Call method 2");
}
}
ในตัวอย่าง เรามีเมธอด Callback ()
ซึ่งมีพารามิเตอร์เป็น delegate และเราได้เรียกใช้เมธอดที่ส่งเข้ามาภายในเมธอด Callback() แทน
Delegates กับอาเรย์
คุณสามารถเรียกใช้เมธอดแบบไดนามิกส์ได้ โดยเราสามารถสร้าง delegate ให้เป็นอาเรย์แล้วเรียกใช้ด้วย index ของมัน ซึ่ง delegate ก็เป็นออบเจ็คหนึ่งดังนั้นมันก็เหมือนกับอาเรย์ของออบเจ็คนั้นเอง
using System;
class DelegatesExample5
{
delegate float MeDelegate(int[] n);
static void Main(string[] args)
{
const int SIZE = 4;
int[] number = { 2, 8, 5, 10, -3, 4, -1, 7};
float[] result = new float[SIZE];
MeDelegate[] de = { FindMin, FindMax, FindSum, FindAvg };
for (int i = 0; i < SIZE; i++) {
result[i] = de[i](number);
}
Console.Write("Array: ");
for (int i = 1; i < number.Length; i++)
{
Console.Write(number[i] + ", ");
}
Console.WriteLine("\nMin: " + result[0]);
Console.WriteLine("Max: " + result[1]);
Console.WriteLine("Sum: " + result[2]);
Console.WriteLine("Avg: " + result[3]);
}
static float FindMin (int[] n)
{
int min = n[0];
for (int i = 1; i < n.Length; i++) {
if (n[i] < min)
min = n[i];
}
return min;
}
static float FindMax(int[] n)
{
int max = n[0];
for (int i = 1; i < n.Length; i++)
{
if (n[i] > max)
max = n[i];
}
return max;
}
static float FindSum(int[] n)
{
int sum = 0;
for (int i = 1; i < n.Length; i++)
{
sum += n[i];
}
return sum;
}
static float FindAvg (int[] n)
{
return ((float) FindSum(n)) / n.Length;
}
}
ในตัวอย่าง เราได้สร้างอาเรย์ของ delegate นั่นหมายความว่าเราสามารถกำหนดเมธอดทั้งหมดของเราไว้ในอาเรย์ได้ เราได้สร้างฟังก์ชันสำหรับหาค่าน้อยสุด มากสุด ผลรวม และค่าเฉลี่ยจากอาเรย์ของตัวเลข และเราได้เรียกใช้ฟังก์ชันทั้งหมดผ่านทางอาเรย์ของ delegate
Array: 8, 5, 10, -3, 4, -1, 7,
Min: -3
Max: 10
Sum: 30
Avg: 3.75
นี่เป็นผลลัพธ์ของโปรแกรม
Anonymous methods
Anonymous methods คือเมธอดที่ไม่มีชื่อ โดยเมธอดจะสามารถเขียนแทรกลงในเมธอดอื่นได้ภายในโปรแกรม นี่เป็นตัวอย่างการสร้าง anonymous methods ในภาษา C#
using System;
using System.Threading;
class AnonymouseMothod
{
delegate void MeDelegate();
static void Main(string[] args)
{
// basic anomymous method
MeDelegate de = delegate
{
Console.WriteLine("Anonymouse is invoked.");
};
de();
// basic anomymous method with thread
Thread t = new Thread(new ThreadStart(delegate
{
Console.WriteLine("Anonymouse method in thread.");
}));
t.Start();
}
}
ในตัวอย่างเป็นการสร้าง anonymous method แบบธรรมดาโดย delegate และการสร้างสำหรับให้ thread ทำงาน และ anonymous method จะถูกใช้บ่อยๆ กับ event ซึ่งอำนวยความสะดวกและง่ายต่อการเขียนโปรแกรม ไม่ต้องแยกเมธอดไว้คนละที
ในบทนี้ คุณได้เรียนรู้เกี่ยวกับ delegate ในภาษา C# และการใช้งานในสภานการณ์ต่างๆ ซึ่งสามารถอำนวยความสะดวกในการออกแบบโปรแกรม