What are Delegates in C#?
ببساطة، نقدر نقول إن الـ delegates في لغة C# هي Pointer لـ Function بس أمان من ناحية النوع (Type-Safe Function Pointer). ده معناه إنها بتحمل reference لـ method أو function، وبعدين بتستدعي الـ method دي عشان تتنفذ.
عشان نقرب الفكرة، تخيل إن الـ Delegate ده عامل زي “المندوب” أو إنك بتعمل “تفويض”.
لو إنت مدير في شركة وعايز تدي مهمة لموظف، إنت ممكن تختار أي موظف يعمل المهمة دي من غير ما تعرف اسمه، المهم يكون عنده نفس الشروط (مثلاً: خبرة في مجال معين).
في البرمجة، الـ Delegate هو نوع بيشاور لـ method معينة، وبيسمحلك تستدعي أي method من خلاله طالما “شكلهم” واحد (نفس الـ Signature، يعني نفس عدد وأنواع الـ parameters ونفس نوع الـ return type). كل اللي بتعرفه عنها هو الـ Signature، لكن هي فين؟ في أي class؟ أو بتعمل إيه؟ كل ده ميخصكش. إنت بتناديها وبتبعتلها الـ parameters وهي بترجعلك النتيجة.
Why use Delegates?
- تجنب الـ
if-elseالكتير: زي ما هنشوف في مثال الآلة الحاسبة، بدل ما تعمل شروط كتير، تقدر تاخد العملية الحسابية نفسها كـparameter. - المرونة (Flexibility): تقدر تضيف عمليات جديدة أو تغير السلوك من غير ما تغير أو تعدل في الكود الأساسي.
- الاستخدام في الـ Event: أغلب أنظمة الـ UI (زي إنك تضغط على زرار) بتستخدم
Delegates.
The Calculator Example: Before and After
عشان نفهم قوة الـ Delegates بجد، خلينا نعمل 4 methods بسيطة للعمليات الحسابية:
public static int Add(int num1, int num2)
{
Console.WriteLine("Add Method Called");
return num1 + num2;
}
public static int Subtract(int num1, int num2)
{
Console.WriteLine("Subtract Method Called");
return num1 - num2;
}
public static int Multiply(int num1, int num2)
{
Console.WriteLine("Multiply Method Called");
return num1 * num2;
}
public static int Divide(int num1, int num2)
{
Console.WriteLine("Divide Method Called");
return num1 / num2;
}The Old Way (Without Delegates)
الطريقة القديمة إننا نبعت parameter يحدد العملية المطلوبة ونستخدم if-else أو switch:
public static void Calculator(int a, int b, char op)
{
int result = 0;
if (op == '+')
result = Add(a, b);
else if (op == '-')
result = Subtract(a, b);
else if (op == '*')
result = Multiply(a, b);
else if (op == '/')
result = Divide(a, b);
else
throw new ArgumentException("Invalid Operator");
Console.WriteLine($"Result: {result}");
}
// Main
Calculator(10, 2, '+'); // 12
Calculator(10, 2, '-'); // 8الـ method دي فيها مشاكل كتير:
- محدودة: بتدعم 4 عمليات بس. لو حبيت أزود عملية (زي باقي القسمة
%)، لازم أرجع أعدل في الكود. - غير مرنة: مش هتقدر تعمل بيها عمليات معقدة.
- معقدة: الـ
if-elseالكتير بيخليها معقدة وضد مبادئ الـClean Code.
The New Way (With Delegates)
هنرمي الـ if-else دي خالص. هنعرف delegate كالتالي:
// This delegate can point to any method that takes two integers and returns an integer.
public delegate int CalculatorDelegate(int a, int b);ونعدل الـ Calculator عشان تستقبل الـ delegate:
public static void CalculatorWithDelegate(int a, int b, CalculatorDelegate operation)
{
// Invoke the delegate directly
int result = operation(a, b);
Console.WriteLine($"Result: {result}");
}شفت البساطة؟ دلوقتي بنناديها كالتالي:
static void Main()
{
// Pass the method name directly as a parameter
CalculatorWithDelegate(10, 2, Add); // 12
CalculatorWithDelegate(10, 2, Subtract); // 8
CalculatorWithDelegate(10, 2, Multiply); // 20
CalculatorWithDelegate(10, 2, Divide); // 5
}مهم جداً: إحنا بنبعت اسم الـ method بس (زي Add)، مش بنناديها. الـ delegate هو اللي بيناديها من جوه.
How to Create a Custom Delegate?
انك تعمل custom delegate عملية بسيطة جداً. بنستخدم الكلمة delegate. الكلمة دي تعتبر سحرية شوية، لإن وراء الكواليس، لما الـ compiler بيشوف الـ delegate keyword، هو في الحقيقة بينشئ class بيورث من delegate classes تانية في .NET Framework.
الـ syntax عشان نعمل delegate شبه الـ abstract method جداً، الفرق بس إننا بنستخدم delegate بدل abstract:
<Access Modifier> delegate <Return Type> <Delegate Name> (Parameter List);ده مثال عملي على delegate:
public delegate void WorkPerformedHandler(int hours, WorkType workType);الـ delegate ده ممكن تفكر فيه على إنه خط أنابيب (pipeline) في اتجاه واحد. هو بيرجع void، يعني مفيش حاجة هترجع، البيانات بس بتمشي لقدام. اسم الـ delegate هو WorkPerformedHandler وبياخد اتنين parameters.
البيانات هتتنقل باستخدام الـ pipeline ده. في الحالة دي، الـ pipeline بيقبل بس اتنين parameters ولازم يكونوا من نوع int و WorkType، وإلا مش هيتعمله compile.
الـ delegate يعتبر blueprint للـ method اللي هتنقل البيانات للـ event handler. اللي بنكون عايزينه هو طريقة ننقل بيها شوية بيانات من (Point A) لـ (Point B) اللي هي هتبقى الـ Handler method بتاعتنا.
قاعدة مهمة جداً: الـ signature بتاع الـ delegate والـ handler method signature لازم يكونوا متطابقين. بما إننا عرفنا الـ delegate باتنين parameters، يبقى الـ handler لازم يكون عنده نفس العدد، والنوع، والترتيب. أسماء الـ parameters مش مهمة، المهم النوع والترتيب والعدد.
// The delegate signature
public delegate void WorkPerformedHandler(int hours, WorkType workType);
// The handler method signature must match the delegate's
public static void Manager_WorkPerformed(int workHours, WorkType wType)
{
// Implementation
}How to use Delegates in C#?
عشان تستدعي method باستخدام delegates، لازم تتبع الـ 3 خطوات دي:
- الـ Declare a Delegate: تعلن عن الـ
delegate. - الـ Instantiate a Delegate: تعمل
instanceمنه وتمررله اسم الـmethod(الـHandler Method). لو هيstaticبتناديها باسمها أو باسم الـclass، ولوnon-staticبتناديها عن طريقobject instance. - الـ Invoke a Delegate: تستدعي الـ
delegate.
Basic Invocation Example
بنفس الطريقة اللي بنستدعي بيها method عادية، نقدر نستدعي الـ delegate، أو نستخدم الـ Invoke method.

using System;
namespace DelegatesDemo
{
// 1. Declare
public delegate void WorkPerformedHandler(int hours, WorkType workType);
class Program
{
static void Main(string[] args)
{
// 2. Instantiate (Manager_WorkPerformed is the handler)
WorkPerformedHandler del1 = new WorkPerformedHandler(Manager_WorkPerformed);
// 3. Invoke (Dynamic call at runtime)
del1(10, WorkType.Golf);
// del1.Invoke(50, WorkType.GotoMeetings); // This also works
Console.ReadKey();
}
// Match the delegate signature
public static void Manager_WorkPerformed(int workHours, WorkType wType)
{
Console.WriteLine("Work Performed by Event Handler");
Console.WriteLine($"Work Hours: {workHours}, Work Type: {wType}");
}
}
public enum WorkType
{
Golf,
GotoMeetings,
GenerateReports
}
}Output:
Work Performed by Event Handler
Work Hours: 10, Work Type: GolfDifferent Ways to Use Delegates
فيه كذا طريقة نقدر نبعت بيهم الـ logic للـ delegate:
1. الـDirectly: زي المثال اللي فات (بنبعت اسم الـ method).
2. الـ Variable: نعمل متغير من نوع الـ delegate.
CalculatorDelegate myDelegate = Add;
CalculatorWithDelegate(10, 2, myDelegate);
myDelegate = Subtract;
CalculatorWithDelegate(10, 2, myDelegate);3. Anonymous Methods (Old way):
لو العملية بسيطة، نكتبها من غير ما نعمل method منفصلة.
CalculatorWithDelegate(10, 2, delegate(int n1, int n2) {
return n1 * n2;
});4. Lambda Expressions (Modern and Preferred way):
طريقة مختصرة وأقوى بكثير (تسمى Arrow Function).
// Lambda expression for multiplication
CalculatorWithDelegate(10, 5, (a, b) => a * b); // 50
// Lambda expression for division
CalculatorWithDelegate(10, 2, (x, y) => x / y); // 5
// Adding Modulus without changing the main method!
CalculatorWithDelegate(10, 3, (x, y) => x % y); // 1Callbacks using Delegates
الـ Delegates بتُستخدم عشان نستدعي call-back functions. ده معناه إننا هنستدعي function ونمرر delegate instance كـ parameter ليها، ونتوقع إنها تستدعي الـ delegate في وقت معين.
using System;
namespace DelegatesDemo
{
public delegate void CallbackMethodHandler(string message);
class Program
{
static void Main(string[] args)
{
Program obj = new Program();
CallbackMethodHandler del1 = new CallbackMethodHandler(obj.CallbackMethod);
// Pass the delegate to another method
DoSomework(del1);
Console.ReadKey();
}
public static void DoSomework(CallbackMethodHandler del)
{
Console.WriteLine("Processing some Task");
// Invoke the callback method via the delegate
del("Pranaya");
}
public void CallbackMethod(string message)
{
Console.WriteLine("CallbackMethod Executed");
Console.WriteLine($"Hello: {message}, Good Morning");
}
}
}Output:
Processing some Task
CallbackMethod Executed
Hello: Pranaya, Good MorningAnother Practical Example: Filtering Employees
تخيل عندنا List من الموظفين وعايزين نعمل method تحسب مرتباتهم بناءً على شروط متغيرة (مثلاً اللي راتبه أقل من 2000، أو اللي اسمه بيبدأ بحرف معين).
public class Employee
{
public string Name { get; set; }
public int Salary { get; set; } // BasicSalary
}بدل ما نعمل if conditions كتير جوه الـ method، هنخليها تستقبل delegate يرجع boolean:
public delegate bool FilterDelegate(Employee emp);
public static void ProcessSalaries(List<Employee> employees, FilterDelegate filter)
{
foreach (var emp in employees)
{
// Use the delegate to check if we should process this employee
if (filter(emp))
{
Console.WriteLine($"Processing salary for {emp.Name}");
}
}
}دلوقتي نقدر نمرر أي شرط إحنا عايزينه باستخدام Lambda:
// Process salaries for employees with Salary < 2000
ProcessSalaries(employees, emp => emp.Salary < 2000);
// Process salaries for employees with Salary > 5000
ProcessSalaries(employees, emp => emp.Salary > 5000);
// Process salaries for names starting with "Employee 5"
ProcessSalaries(employees, emp => emp.Name.StartsWith("Employee 5"));الـ method دلوقتي متعرفش حاجة عن الـ business rules، هي بتلف وتسأل الـ delegate بس.
Types of Delegates
- الـ Single Cast Delegate: الـ
delegateبيشير لـmethodواحدة بس. - الـ Multicast Delegate: الـ
delegateبيشير لأكتر منmethodفي نفس الوقت.
Deep Dive into Multicast Delegates
تقدر تخلي المندوب يشير لأكتر من method باستخدام علامة +=.
CalculatorDelegate multiDelegate = Add;
multiDelegate += Subtract;
multiDelegate += Multiply;
multiDelegate += Divide;
CalculatorWithDelegate(10, 2, multiDelegate);إيه اللي هيحصل؟
لما يتنادى، هينفذ الـ methods دي بالترتيب (Add ثم Subtract وهكذا). النتيجة النهائية اللي هترجع هتكون نتيجة آخر method اتنفذت (Divide).
وممكن نشيل method باستخدام -=:
multiDelegate -= Multiply; // Remove the Multiply methodتحذير: لو فضلت تشيل methods لحد ما الـ delegate بقى فاضي وبيشاور على null وحاولت تناديه، هيضرب NullReferenceException.
Rules and Usage of Delegates
القواعد الأساسية:
- الـ
Delegateهوuser-defined type، لازم تعرّفه الأول. - الـ
Signatureلازم يكون متطابق عشان متخدشcompiler error.
بنستخدمهم فين؟
Event HandlersCallbacks- تمرير
MethodsكـParameters LINQMultithreading
What happens behind the scene?
1. Delegate Base Class
واحد من الـ classes الأساسية جداً في .NET Framework هو Delegate، واللي بيوفر شوية وظائف أساسية. لو روحت لتعريف Delegate class هتلاقيه abstract class.

الـ class ده بيوفر خاصيتين مهمين:
- الـ
public MethodInfo Method {get;}: بتُستخدم عشان تجيب الـmethodاللي بيمثلها الـdelegate(شكلها إيه). - الـ
public object Target {get;}: بتُستخدم عشان تجيب الـclass instanceاللي الـdelegateبيستدعي عليه الـinstance method. (بترجعnullلو الـdelegateبيمثلstatic method).
كمان عنده virtual method مهمة جداً:
- الـ
public virtual Delegate[] GetInvocationList(): بترجع قايمة الـmethodsاللي الـdelegateده بيشاور عليها.
2. MulticastDelegate Base Class
في core class تاني مهم اسمه MulticastDelegate. لو روحت لتعريفه هتلاقيه برضه abstract class وبيورث من الـ Delegate abstract class.
كل delegate إحنا بنعمله في الكود، لما بيتعمله compile، بيورث أوتوماتيك من MulticastDelegate. وده اللي بيدينا القدرة إننا نخلي الـ delegate يشيل أكتر من method في نفس الوقت.
graph TD A[System.Object] --> B[System.Delegate] B --> C[System.MulticastDelegate] C --> D[Your Custom Delegate] style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#bbf,stroke:#333,stroke-width:2px style C fill:#bbf,stroke:#333,stroke-width:2px style D fill:#dfd,stroke:#333,stroke-width:2px
ملاحظة: في الكود بتاعك، متقدرش تورث بشكل مباشر من Delegate أو MulticastDelegate. الطريقة الوحيدة هي إنك تستخدم delegate keyword والـ compiler هيعمل الباقي. لو بصيت على الـ IL Code بتاع الـ delegate، هتلاقيه عبارة عن sealed class بيعمل extends لـ MulticastDelegate.
Delegate Properties and Methods in Action
زي ما قلنا فوق عن خصائص الـ Delegate class، خلينا نشوفهم في الكود:
using System;
using System.Reflection;
namespace DelegatesDemo
{
public delegate void DoSomeMethodHandler(string message);
class Program
{
static void Main(string[] args)
{
SomeClass obj = new SomeClass();
DoSomeMethodHandler del1 = new DoSomeMethodHandler(obj.DoSomework);
// Get information about the delegate
MethodInfo Method = del1.Method;
object Target = del1.Target;
Delegate[] InvocationList = del1.GetInvocationList();
Console.WriteLine($"Method Property: {Method}");
Console.WriteLine($"Target Property: {Target}");
foreach (var item in InvocationList)
{
Console.WriteLine($"InvocationList: {item}");
}
}
}
public class SomeClass
{
public void DoSomework(string message)
{
Console.WriteLine("DoSomework Executed");
}
}
}Output:
Method Property: Void DoSomework(System.String)
Target Property: DelegatesDemo.SomeClass
InvocationList: DelegatesDemo.DoSomeMethodHandler- الـ
Method propertyهترجع الـprototypeبتاع الـmethodاللي الـdelegateبيشاور عليها، وفي مثالنا هتبقىVoid DoSomework(System.String). - الـ
Target propertyهترجع اسم الـclassالكامل (fully qualified class name) اللي الـevent handler methodبتنتمي ليه، وفي مثالنا هوDelegatesDemo.SomeClass. - الـ
GetInvocationList methodهترجع قايمة الـdelegatesاللي الـdelegateبيشير ليها، وفي الحالة ديdelegateواحد بس. في مقالنا الجاي، هنفهم الـmulticast delegateوفي الحالة دي هترجع أكتر منdelegate.
Generic Delegates
الـ Generic Delegates هي تحسين قوي بيخليك تعرف delegates بنوع عام (Generic Type)، وده بيخليها:
- أكثر مرونة: بتشتغل مع أنواع بيانات مختلفة.
- أكثر أماناً: بتضمن تطابق الأنواع.
- أقل تكراراً: بتقلل تعريف
delegatesكتير.
لغة C# بتوفر 3 أنواع جاهزة (Built-in) ومهمين جداً:
1. Action<T>
بتُستخدم للـ methods اللي مش بترجع حاجة (void).
Action<string> printAction = s => Console.WriteLine(s);
printAction("Hello Generics!"); // Output: Hello Generics!2. Func<T, TResult>
بتُستخدم للـ methods اللي بترجع قيمة. (آخر Parameter في القوس هو الـ Return Type).
Func<int, int, int> add = (a, b) => a + b;
int result = add(5, 3); // Output: 83. Predicate<T>
بتُستخدم للـ methods اللي بترجع boolean (true أو false).
Predicate<int> isEven = num => num % 2 == 0;
bool test = isEven(4); // Output: trueIntegration with Lists (List<T>)
الأنواع دي بنستخدمها بشكل مكثف مع الـ LINQ وعمليات الـ Lists:
List<int> numbers = new List<int> {1, 2, 3, 4, 5};
// Action with ForEach
numbers.ForEach(n => Console.Write(n + " ")); // 1 2 3 4 5
// Predicate with FindAll
var evens = numbers.FindAll(n => n % 2 == 0); // [2, 4]
// Func with Select
var squares = numbers.Select(n => n * n); // [1, 4, 9, 16, 25]وممكن طبعاً تعمل الـ Generic Delegate بتاعك:
public delegate TOutput MyConverter<TInput, TOutput>(TInput input);
// Using:
MyConverter<int, string> intToString = num => num.ToString();
string result = intToString(42); // "42"Common Pitfalls
- الـ
Null Reference Exception: تأكد دايماً إن الـDelegateمشnullقبل ما تعمل ليهInvoke(ممكن تستخدم?.Invoke()). - الـ
Signature: لازم شكل الـmethodيطابق الـDelegateبالضبط. - الـ
Memory Leaks: لو استخدمتDelegatesمعEvents، متنساش تعملunsubscribe(باستخدام-=) لما تخلص عشان متخليش الذاكرة تتهدر.
Delegate vs Interface
- الـ
Delegate: مناسب للمهام البسيطة اللي بتحتاج تمررmethodواحدة كـCallback. - الـ
Interface: أنسب لو عندك مجموعة من الـMethodsالمترابطة وعايز تفرض “عقد” (Contract) كامل على الـclass.
Notes
- االاستدعاء المباشر للـ
method(Direct Invocation) هو دايماً الأسرع لأن الـDelegateبيضيفoverheadبسيط جداً وقت التنفيذ لأنه بيعملindirect call. ورغم إن الـoverheadده شبه معدوم في التطبيقات الحديثة، إلا إن الـDelegateأبطأ بنسبة طفيفة جداً من الاستدعاء المباشر، وليس أسرع.- في التحديثات الجديدة الخاصة بـ C# 13 وما بعدها وصولاً لـ .NET 10، الـ
Delegatesبقت بتدعم استخدام الـparamskeyword مع كل أنواع الـ Collections (زيSpan<T>وList<T>) مش بس الـ Arrays زي زمان، وده بيحسن جداً من الأداء وبيقلل استهلاك الميموري وقت استدعاء الـDelegatesاللي بتاخد عدد متغير من الـparameters. - الـ Function Pointers (
delegate*): للناس المهتمين بالـ High Performance، الـ C# وفرتFunction Pointersبتُكتب كـdelegate*جوه الـunsafe code، ودي بتديك سرعة استدعاء مماثلة لـ C++ بدون أيMemory AllocationsأوOverheadخاص بالـ Classes بتاعة الـDelegate.
- في التحديثات الجديدة الخاصة بـ C# 13 وما بعدها وصولاً لـ .NET 10، الـ