Delegate یک شیء است که به یک متد اشاره میکند، یا به عبارت دیگر، یک متغیر از نوع مرجع است که میتواند مرجع به متدها را نگه دارد. این یک راه را فراهم میکند که مشخص میکند کدام متد زمانی که یک رویداد فراخوانی میشود، باید اجرا گردد.
در این مقاله، ابتدا به تعریف و نحوه استفاده از Delegate در سی شارپ میپردازیم، سپس نحوه چندگانهسازی «Multicasting» و ویژگیهای کلیدی آنها را بررسی میکنیم. همچنین به مفاهیم پیشرفتهتر مانند متدهای ناشناس و عبارات لامبدا که از Delegate در سی شارپ بهره میبرند، اشاره خواهیم کرد. اگر قصد دارید درک بهتری از نحوه استفاده از Delegate در سی شارپ داشته باشید، این مقاله راهنمایی جامع برای شما خواهد بود.
مقدمه
در زبان برنامهنویسی #C، نماینده ها «Delegates» یکی از مفاهیم کلیدی برای مدیریت روشهای بازگشتی «Callback»، رویدادها و برنامهنویسی پویا هستند. نماینده ها به عنوان اشارهگرهای نوع ایمن به متدها عمل کرده و این امکان را فراهم میکنند که یک متد خاص را بدون نیاز به دانستن جزئیات پیادهسازی آن، فراخوانی کنیم. این ویژگی در توسعه نرمافزارهای مدرن، به ویژه در برنامهنویسی رویدادمحور، چندنخی و طراحی الگوهای انعطافپذیر، کاربرد گستردهای دارد.
برای مثال، اگر شما روی یک دکمه در یک فرم (برنامه فرمهای ویندوزی) کلیک کنید، برنامه یک متد خاص را فراخوانی خواهد کرد. به زبان ساده، این یک نوع است که مرجعهایی به متدها با لیست پارامتر خاص و نوع بازگشتی معین را نشان میدهد و سپس زمانی که نیاز است، متد را در برنامه برای اجرا فراخوانی میکند.
تعریف Delegate در سی شارپ
نوع Delegate میتواند با استفاده از کلمه کلیدی delegate تعریف «Declaration» شود. پس از اعلان یک delegate، نمونه delegate به متدهایی که نوع بازگشتی و لیست پارامترهایشان با delegate واسطه تطابق دارد، اشاره کرده و آنها را فراخوانی خواهد کرد.
[modifier] delegate [return_type] [delegate_name] ([parameter_list]);
- modifier: این اصلاحگر مورد نیاز است که دسترسی به delegate را تعریف میکند و استفاده از آن اختیاری است.
- delegate: این کلمه کلیدی است که برای تعریف واسطه استفاده میشود.
- return_type: نوع مقداری است که توسط متدهایی که واسطه فراخوانی خواهد کرد، بازگردانده میشود. این میتواند void باشد. یک متد باید همان نوع بازگشتی را داشته باشد که واسطه دارد.
- delegate_name: این نام یا شناسهای است که توسط کاربر برای واسطه تعریف میشود.
- parameter_list: این شامل پارامترهایی است که توسط متد زمانی که از طریق واسطه فراخوانی میشود، مورد نیاز هستند.
مثال
// “public” is the modifier // “int” is return type // “ProgramStore” is delegate name // “(int G, int F, int G)” are the parameters public delegate int ProgramStore(int G, int F, int G);
توجه: یک Delegate تنها یک متدی را فراخوانی خواهد کرد که با امضای آن و نوع بازگشتیاش سازگار باشد. یک متد میتواند یک متد استاتیک مرتبط با یک کلاس باشد یا یک متد نمونه مرتبط با یک شیء، مهم نیست.
فراخوانی Delegate در سی شارپ
پس از تعریف یک Delegate در سی شارپ، یک شیء Delegate با کمک کلمه کلیدی new ایجاد میشود. زمانی که یک delegate ایجاد شد، یک فراخوانی متد به delegate به آن متد منتقل میشود. پارامترهایی که توسط فراخوانیکننده به delegate منتقل میشوند، به متد منتقل میشوند و مقدار بازگشتی، در صورت وجود، از متد به فراخوانیکننده توسط delegate باز میگردد. این فرآیند به نام فراخوانی delegate شناخته میشود.
ساختار یا Syntax
[delegate_name] [instance_name] = new [delegate_name](calling_method_name);
مثال
// Using of Delegates using System; class PStore { // Declaring the delegates // Here return type and parameter type should // be same as the return type and parameter type // of the two methods // "addnum" and "subnum" are two delegate names public delegate void addnum(int a, int b); public delegate void subnum(int a, int b); public void sum(int a, int b) { Console.WriteLine("(100 + 40) = {0}", a + b); } public void subtract(int a, int b) { Console.WriteLine("(100 - 60) = {0}", a - b); } // Main Method public static void Main(String []args) { // creating object "obj" of class "PStore" PStore obj = new PStore(); // creating object of delegate, name as "del_obj1" // for method "sum" and "del_obj2" for method "subtract" & // pass the parameter as the two methods by class object "obj" // instantiating the delegates addnum del_obj1 = new addnum(obj.sum); subnum del_obj2 = new subnum(obj.subtract); // pass the values to the methods by delegate object del_obj1(100, 40); del_obj2(100, 60); // These can be written as using // "Invoke" method // del_obj1.Invoke(100, 40); // del_obj2.Invoke(100, 60); } }
خروجی
(۱۰۰ + ۴۰) = 140 (۱۰۰ - ۶۰) = 40
توضیح: در برنامه بالا، دو delegate به نامهای addnum و subnum وجود دارند. ما شیء obj از کلاس PStore را ایجاد میکنیم چون هر دو متد (addnum و subnum) متدهای نمونه هستند. بنابراین برای فراخوانی آنها به یک شیء نیاز داریم. اگر متدها استاتیک باشند، دیگر نیازی به ایجاد شیء کلاس نیست.
چندگانهسازی Delegate در سی شارپ
چندگانهسازی Delegate در سی شارپ یک گسترش از Delegate معمولی (که گاهی به آن واسطه تککست گفته میشود) است. این به کاربر کمک میکند تا بیشتر از یک متد را در یک فراخوانی واحد هدف قرار دهد.
ویژگی های چندگانهسازی Delegate
Delegateها ترکیب میشوند و وقتی شما یک Delegate را فراخوانی میکنید، فهرست کامل متدها فراخوانی میشود.
- تمام متدها در ترتیب اول به اول (FIFO) فراخوانی میشوند.
- از عملگر ‘+’ یا ‘+= ‘ برای اضافه کردن متدها به Delegateها استفاده میشود.
- از عملگر ‘–’ یا ‘–=’ برای حذف متدها از لیست Delegateها استفاده میشود.
توجه: به یاد داشته باشید که چندگانهسازی واسطه باید نوع بازگشتی Void داشته باشد، در غیر این صورت یک استثنای زمان اجرا رخ خواهد داد. همچنین، در چندگانهسازی Delegate، تنها مقدار بازگشتی از آخرین متدی که به چندگانه اضافه شده، باز خواهد گشت. با این حال، دیگر متدها به درستی اجرا خواهند شد.
مثال: برنامه زیر نحوه چندگانهسازی نماینده ها (Multicasting Delegates) را در #C نشان میدهد. در اینجا، یک Delegate برای دو متد مختلف تنظیم شده است، و هر دو متد در یک فراخوانی اجرا میشوند.
// C# program to illustrate the // Multicasting of Delegates using System; class rectangle { // declaring delegate public delegate void rectDelegate(double height, double width); // "area" method public void area(double height, double width) { Console.WriteLine("Area is: {0}", (width * height)); } // "perimeter" method public void perimeter(double height, double width) { Console.WriteLine("Perimeter is: {0} ", 2 * (width + height)); } // Main Method public static void Main(String []args) { // creating object of class // "rectangle", named as "rect" rectangle rect = new rectangle(); // these two lines are normal calling // of that two methods // rect.area(6.3, 4.2); // rect.perimeter(6.3, 4.2); // creating delegate object, name as "rectdele" // and pass the method as parameter by // class object "rect" rectDelegate rectdele = new rectDelegate(rect.area); // also can be written as // rectDelegate rectdele = rect.area; // call 2nd method "perimeter" // Multicasting rectdele += rect.perimeter; // pass the values in two method // by using "Invoke" method rectdele.Invoke(6.3, 4.2); Console.WriteLine(); // call the methods with // different values rectdele.Invoke(16.3, 10.3); } }
خروجی
Area is: 26.46 Perimeter is: 21 Area is: 167.89 Perimeter is: 53.2
- در برنامه بالا، ما از نماینده ها (Delegates) برای فراخوانی چندین متد با یک فراخوانی واحد استفاده کردیم.
- با استفاده از عملگر += متدهای مختلف را به یک واسطه اضافه کردیم (Multicasting).
- ترتیب اجرای متدها در چندگانهسازی Delegateها FIFO است.
- این تکنیک در برنامهنویسی رویدادمحور (Event-driven Programming) و فراخوانی متدهای مرتبط (Chained Method Calls) بسیار کاربردی است.
نکات مهم درباره Delegate در سی شارپ
- Delegateها روش خوبی برای کپسولهسازی متدها فراهم میکنند.
- Delegateها کلاس کتابخانهای در فضای نام System هستند.
- اینها اشارهگرهای نوع ایمن به هر متدی هستند.
- Delegateها عمدتاً در پیادهسازی متدهای بازگشتی (callback) و رویدادها استفاده میشوند.
- Delegateها میتوانند به هم زنجیر شوند، به طوری که دو یا بیشتر متد میتوانند در یک رویداد فراخوانی شوند.
- Delegateها به کلاسی که شیء آن به آن اشاره میکند اهمیتی نمیدهند.
- Delegateها میتوانند برای فراخوانی متدهای ناشناس نیز استفاده شوند.
متدهای ناشناس (C# 2.0) و عبارات لامبدا (C# 3.0) در برخی از زمینهها به نوعهای واسطه کامپایل میشوند. گاهی اوقات، این ویژگیها به طور مشترک به عنوان توابع ناشناس شناخته میشوند.
نتیجهگیری
Delegate در سی شارپ یکی از مفاهیم کلیدی برای مدیریت و ارجاع به متدها به صورت انعطافپذیر و پویا هستند. آنها امکان برنامهنویسی رویدادمحور، فراخوانی متدهای بازگشتی «Callback» و چندگانهسازی متدها را فراهم میکنند. علاوه بر این، نماینده ها به عنوان پایهای برای متدهای ناشناس و عبارات لامبدا عمل کرده و به توسعهدهندگان این امکان را میدهند که کدهای خواناتر و ساختاریافتهتری بنویسند.
با یادگیری نحوه استفاده از نمایندهها، برنامهنویسان میتوانند کدهای منعطفتر، قابل استفاده مجدد و مقیاسپذیرتری بنویسند. درک این مفهوم به ویژه در مدیریت رویدادها، برنامهنویسی چندنخی و طراحی الگوهای پیشرفته بسیار ارزشمند است. بنابراین، یادگیری و استفاده صحیح از واسطهها میتواند به بهبود کیفیت و عملکرد برنامههای C# کمک کند.