หากคุณเป็นโปรแกรมเมอร์ C ผู้รับมอบสิทธิ์ถือเป็นตัวชี้ไปยังฟังก์ชันได้ อย่างไรก็ตาม ผู้รับมอบสิทธิ์ใน C # เป็นมากกว่าตัวชี้ฟังก์ชันทั่วไป บทความนี้อธิบายแนวคิดของผู้รับมอบสิทธิ์และการนำไปใช้ในการเขียนโปรแกรมแบบวันต่อวัน
โดยพื้นฐานแล้ว ผู้ได้รับมอบหมายให้ระดับของทางอ้อม พวกเขาห่อหุ้มส่วนของรหัสที่สามารถส่งผ่านไปมาและดำเนินการในลักษณะที่ปลอดภัยต่อการพิมพ์ แทนที่จะดำเนินการตามลักษณะการทำงานทันที พฤติกรรมดังกล่าวจะอยู่ในอ็อบเจ็กต์ มีการดำเนินการหลายอย่างที่คุณสามารถดำเนินการกับออบเจ็กต์นั้นได้ และหนึ่งในนั้นกำลังดำเนินการที่มีพฤติกรรมดังกล่าว
การใช้ผู้รับมอบสิทธิ์ช่วยให้เราเขียนฟังก์ชันที่มีลำดับสูงกว่า เช่น ฟังก์ชันที่สามารถรับฟังก์ชันเป็นพารามิเตอร์ หรือฟังก์ชันส่งคืนเป็นค่าที่ส่งกลับ ประเภทผู้รับมอบสิทธิ์กำหนดลายเซ็นวิธีการที่ผู้รับมอบสิทธิ์สามารถเป็นตัวแทนได้ โดยเฉพาะประเภทการส่งคืนของวิธีการและประเภทพารามิเตอร์ ในตัวอย่างต่อไปนี้ Transformer เป็นผู้รับมอบสิทธิ์ที่สามารถแสดงวิธีการใดๆ ที่ยอมรับและส่งกลับจำนวนเต็ม
delegate int Transformer(int x);
เราสามารถกำหนดวิธีการใดๆ (รวมถึง lambdas, instance, หรือ static method) ให้กับอินสแตนซ์ของ Transformer ที่เติมเต็มลายเซ็น ตัวอย่างเช่น −
Transformer square = x => x * x; Transformer cube = x => x * x * x; Console.WriteLine(square(3)); // prints 9 Console.WriteLine(cube(5)); // prints 125
ควรใช้ผู้แทนเมื่อใด
โดยทั่วไปแล้วผู้รับมอบสิทธิ์จะใช้เมื่อโค้ดที่ต้องการดำเนินการบางอย่างไม่ทราบรายละเอียดว่าการกระทำเหล่านั้นควรเป็นอย่างไร แต่รู้อินเทอร์เฟซของการกระทำเหล่านั้น
ในการเขียนโปรแกรม เรามักจะเผชิญกับสถานการณ์ที่เราต้องดำเนินการบางอย่าง แต่เราไม่ทราบล่วงหน้าว่าเราจะต้องการเรียกใช้วิธีการใดเพื่อดำเนินการ ผู้รับมอบสิทธิ์ช่วยเราแก้ปัญหานี้โดยแทนที่พฤติกรรมนั้นด้วยผู้รับมอบสิทธิ์ จากนั้นส่งตัวอย่างที่เป็นรูปธรรมของผู้ได้รับมอบหมายนั้นด้วยพฤติกรรมที่เหมาะสมตามความจำเป็นของบริบทและสถานการณ์
เพื่อให้ผู้รับมอบสิทธิ์ทำอะไรได้ ต้องมีสี่สิ่งเกิดขึ้น –
1) ต้องประกาศประเภทผู้รับมอบสิทธิ์
ประเภทผู้รับมอบสิทธิ์คือคำจำกัดความของฟังก์ชันที่แสดงเป็นหลัก กล่าวคือ ประกอบด้วยประเภทพารามิเตอร์ที่ฟังก์ชันจะยอมรับและประเภทส่งคืนที่ฟังก์ชันดังกล่าวจะส่งคืน
ตัวอย่างเช่น ประเภทผู้รับมอบสิทธิ์ที่แสดงถึงวิธีการที่รับสองตัวเลขเป็นอินพุตและส่งกลับตัวเลขสามารถประกาศเป็น −
delegate int Processor(int numOne, int numTwo);
ตัวประมวลผลเป็นประเภทที่คล้ายกับประเภทที่สร้างโดยคลาส ในการสร้างอินสแตนซ์ประเภทนี้ คุณต้องมีวิธีการที่รับตัวเลขสองตัวเป็นอินพุตและส่งกลับบูล
2) รหัสที่จะดำเนินการต้องอยู่ในวิธีการ
กำหนดวิธีการที่มีลายเซ็นเหมือนกันทุกประการกับประเภทผู้รับมอบสิทธิ์ด้านบน และนั่นคือสิ่งที่คุณต้องการตามสถานการณ์ขณะรันไทม์ ตัวอย่างเช่น สามารถใช้วิธีการใดๆ ต่อไปนี้เพื่อสร้างอินสแตนซ์ของตัวประมวลผล เนื่องจากทั้งหมดใช้ตัวเลขสองตัวและส่งคืนตัวเลข
static int Add(int numOne, int numTwo){ Return numOne + numTwo; } static int Subtract(int numOne, int numTwo){ Return numOne - numTwo; }
3) ต้องสร้างอินสแตนซ์ผู้รับมอบสิทธิ์
ตอนนี้ คุณมีประเภทผู้รับมอบสิทธิ์และวิธีการที่มีลายเซ็นที่ถูกต้องแล้ว คุณสามารถสร้างอินสแตนซ์ของประเภทผู้รับมอบสิทธิ์นั้นได้ ในการทำเช่นนี้ เรากำลังบอกให้คอมไพเลอร์ C# รันเมธอดนี้เมื่อมีการเรียกใช้อินสแตนซ์ของผู้รับมอบสิทธิ์
Processor processorOne = new Processor(Add); Processor processorTwo = new Processor(Subtract);
ตัวอย่างข้างต้นถือว่าวิธีการบวกและการลบถูกกำหนดในคลาสเดียวกันกับที่เรากำลังสร้างอินสแตนซ์ของผู้รับมอบสิทธิ์ หากมีการกำหนดเมธอดในคลาสอื่น เราจำเป็นต้องมีอินสแตนซ์ของคลาสนั้น
4) ต้องเรียกใช้อินสแตนซ์ผู้รับมอบสิทธิ์
นี่เป็นเพียงเรื่องของการเรียกใช้เมธอดบนอินสแตนซ์ของผู้รับมอบสิทธิ์ ซึ่งมีชื่อว่า Invoke อย่างไม่น่าแปลกใจ เมธอดนี้บนอินสแตนซ์ผู้รับมอบสิทธิ์มีรายการพารามิเตอร์และประเภทส่งคืนเดียวกันกับที่ประกาศประเภทผู้รับมอบสิทธิ์ระบุ Calling Invoke จะดำเนินการกับอินสแตนซ์ของผู้รับมอบสิทธิ์
int sum = processorOne.Invoke(3, 5);
อย่างไรก็ตาม C # ทำให้ง่ายยิ่งขึ้น คุณสามารถเรียกใช้อินสแตนซ์ผู้รับมอบสิทธิ์ได้โดยตรงราวกับว่ามันเป็นวิธีการในตัวเอง ตัวอย่างเช่น
int difference = processorTwo(10, 6);
การรวมและการลบผู้ได้รับมอบหมาย
หากเราต้องการดำเนินการรายการของการกระทำต่างๆ ด้วยการเรียกใช้อินสแตนซ์ของผู้รับมอบสิทธิ์เพียงครั้งเดียว C# ก็อนุญาตให้เราทำได้ ระบบ. ประเภทผู้รับมอบสิทธิ์มีวิธีการคงที่สองวิธี เรียกว่า รวมและลบ
1. ผสมผสาน
สร้างผู้รับมอบสิทธิ์ใหม่พร้อมรายการการเรียกใช้ที่เชื่อมรายการการเรียกใช้ของผู้รับมอบสิทธิ์ที่ส่งผ่านเป็นพารามิเตอร์ เมื่ออินสแตนซ์ผู้รับมอบสิทธิ์ใหม่ถูกเรียกใช้ การดำเนินการทั้งหมดจะถูกดำเนินการตามลำดับ
public static Delegate Combine(params Delegate[] delegates); // OR public static Delegate Combine(Delegate a, Delegate b);
หากการดำเนินการใด ๆ ในรายการคำขอมีข้อยกเว้น ซึ่งจะป้องกันไม่ให้มีการดำเนินการใดๆ ต่อจากนี้
2. ลบ
ลบรายการการเรียกใช้ของผู้รับมอบสิทธิ์ที่เกิดขึ้นครั้งล่าสุดออกจากรายการการเรียกใช้ของผู้รับมอบสิทธิ์รายอื่น ส่งกลับผู้รับมอบสิทธิ์ใหม่พร้อมรายการการเรียกใช้ที่สร้างขึ้นโดยนำรายการการเรียกใช้ของแหล่งที่มาและลบรายการการเรียกใช้รายการค่าที่เกิดขึ้นล่าสุด
public static Delegate Remove(Delegate source, Delegate value);
สรุป
-
ผู้รับมอบสิทธิ์สรุปพฤติกรรมด้วยประเภทและชุดของพารามิเตอร์เฉพาะ คล้ายกับอินเทอร์เฟซแบบวิธีเดียว
-
ลายเซ็นประเภทที่อธิบายโดยการประกาศประเภทผู้รับมอบสิทธิ์จะกำหนดวิธีที่สามารถใช้เพื่อสร้างอินสแตนซ์ของผู้รับมอบสิทธิ์และลายเซ็นสำหรับการเรียกใช้
-
การสร้างอินสแตนซ์ผู้รับมอบสิทธิ์ต้องใช้วิธีการที่เราต้องการดำเนินการเมื่อมีการเรียกใช้ผู้รับมอบสิทธิ์
-
อินสแตนซ์ของผู้รับมอบสิทธิ์จะไม่เปลี่ยนรูปแบบ คล้ายกับสตริง
-
อินสแตนซ์ของผู้รับมอบสิทธิ์แต่ละรายการมีรายการคำขอ - รายการการดำเนินการ
-
สามารถรวมและลบอินสแตนซ์ของผู้รับมอบสิทธิ์ออกจากกันได้
ตัวอย่าง
using System; class Program{ delegate int Transformer(int x); delegate int Processor(int numOne, int numTwo); static void Main(){ Transformer square = x => x * x; Transformer cube = x => x * x * x; Console.WriteLine(square(3)); // prints 9 Console.WriteLine(cube(5)); // prints 125 Processor processorOne = new Processor(Add); Processor processorTwo = new Processor(Subtract); int sum = processorOne.Invoke(3, 5); Console.WriteLine(sum); // prints 8 int difference = processorTwo(10, 6); Console.WriteLine(difference); // prints 4 } static int Add(int numOne, int numTwo){ return numOne + numTwo; } static int Subtract(int numOne, int numTwo){ return numOne - numTwo; } }
ผลลัพธ์
9 125 8 4