English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
如果我们要将函数作为参数传递怎么办?C#如何处理回调函数或事件处理程序?答案是-委托(delegate)。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。
المعامل هوتحديد إشارة الطريقةنوع البيانات المفردة للمراجع. يمكنك تعريف متغيرات المعامل، مثل أي نوع بيانات آخر، يمكن أن تشير إلى أي طريقة لها نفس إشارة المعامل.
عمل المعامل يتضمن ثلاث خطوات:
إعلان المعامل
تعيين الطريقة المستهدفة
استدعاء المعامل
يمكن استخدام كلمة المفتاح delegate وخطوة التوقيع للمعاملات لإعلان المعاملات، مثلما هو موضح أدناه.
جملة المعامل
[modifier of access] delegate [return type] [name of delegate]([parameters])
إليك إعلانًا للمعامل باسم MyDelegate.
public delegate void MyDelegate(string msg);
في الأعلى، تم إعلان MyDelegate يحتوي على
بعد إعلان المعامل، نحتاج إلى تعيين الطريقة المستهدفة أو تعبير lambda. يمكننا تحقيق ذلك عن طريق إنشاء كائن للمعامل باستخدام كلمة المفتاح new ومرور الطريقة التي تتوافق مع إشارة المعامل.
public delegate void MyDelegate(string msg); // إعلان المعامل // تعيين الطريقة المستهدفة MyDelegate del = new MyDelegate(MethodA); // أو MyDelegate del = MethodA; // أو تعبير lambda MyDelegate del = (string msg) => Console.WriteLine(msg); // طريقة المستهدفة static void MethodA(string message) { Console.WriteLine(message); {}
يمكنك تعيين الطريقة المستهدفة مباشرة من خلال تخصيص الطريقة دون إنشاء كائن للمعامل، مثل MyDelegate del = MethodA.
بعد تعيين الطريقة المستهدفة، يمكنك استخدام طريقة Invoke() أو استخدام() لاستدعاء المعامل.
del.Invoke("Hello World!"); // أو del("Hello World!");
إليك مثالًا كاملاً على المعاملات.
public delegate void MyDelegate(string msg); // إعلان بروتوكول class Program { static void Main(string[] args) { MyDelegate del = ClassA.MethodA; del("Hello World"); del = ClassB.MethodB; del("Hello World"); del = (string msg) => Console.WriteLine("تم استدعاء تعبير lambda: " + msg); del("Hello World"); {} {} class ClassA { static void MethodA(string message) { Console.WriteLine("تم استدعاء ClassA.MethodA() مع المعامل: " + message); {} {} class ClassB { static void MethodB(string message) { Console.WriteLine("تم استدعاء ClassB.MethodB() مع المعامل: " + message); {} {}
الشكل التالي يوضح المعاملات.
الطريقة يمكن أن تحتوي على معاملات نوع الالتزام، مثلما هو موضح أدناه.
public delegate void MyDelegate(string msg); // إعلان بروتوكول class Program { static void Main(string[] args) { MyDelegate del = ClassA.MethodA; InvokeDelegate(del); del = ClassB.MethodB; InvokeDelegate(del); del = (string msg) => Console.WriteLine("تم استدعاء تعبير lambda: " + msg); InvokeDelegate(del); {} static void InvokeDelegate(MyDelegate del) // معامل MyDelegate { del("Hello World"); {} {} class ClassA { static void MethodA(string message) { Console.WriteLine("تم استدعاء ClassA.MethodA() مع المعامل: " + message); {} {} class ClassB { static void MethodB(string message) { Console.WriteLine("تم استدعاء ClassB.MethodB() مع المعامل: " + message); {} {}
في .NET، أنواع Func و Action هي بروتوكولات مدمجة قياسية، ويجب استخدامها لأكثر البروتوكولات شيوعًا بدلاً من إنشاء بروتوكولات مخصصة جديدة.
يمكن للبروتوكولات أن تشير إلى عدة طرق. البروتوكول الذي يشير إلى عدة طرق يُسمى بروتوكول مجموع. تشير علامات '+' أو '+=' إلى إضافة وظيفة إلى قائمة الاستدعاء، بينما تشير علامات '-' و '-=' إلى إزالة وظيفة.
public delegate void MyDelegate(string msg); // إعلان بروتوكول class Program { static void Main(string[] args) { MyDelegate del1 = ClassA.MethodA; MyDelegate del2 = ClassB.MethodB; MyDelegate del = del1 + del2; // del1 + del2 del("Hello World"); MyDelegate del3 = (string msg) => Console.WriteLine("تم استدعاء تعبير lambda: " + msg); del += del3; // del1 + del2 + del3 del("Hello World"); del = del - del2; // إزالة del2 del("Hello World"); del -= del1 // إزالة del1 del("Hello World"); {} {} class ClassA { static void MethodA(string message) { Console.WriteLine("تم استدعاء ClassA.MethodA() مع المعامل: " + message); {} {} class ClassB { static void MethodB(string message) { Console.WriteLine("تم استدعاء ClassB.MethodB() مع المعامل: " + message); {} {}
المعادلات الجبرية الإضافية والطرحية تعمل دائمًا كجزء من التخصيص: del1 += del2؛ وهو متساوي تمامًا مع del1 = del1 + del2؛ والطرح هو نفس الشئ.
إذا كان البروتوكول يعود قيمة، فإن القيمة التي يتم تخصيصها في آخر دالة هدف عند استدعاء بروتوكول التجميع، ستتم العودة.
public delegate int MyDelegate(); // تعريف بروتوكول class Program { static void Main(string[] args) { MyDelegate del1 = ClassA.MethodA; MyDelegate del2 = ClassB.MethodB; MyDelegate del = del1 + del2; Console.WriteLine(del()); // يعود 200 {} {} class ClassA { static int MethodA() { return 100; {} {} class ClassB { static int MethodB() { return 200; {} {}
يمكنك تعريف بروتوكولات泛تاتية بنفس الطريقة التي تعرف بها البروتوكولات، ولكن يمكنك استخدام نوع泛تاتي أو نوع عودة泛تاتي. عند تعيين الهدف للوظيفة، يجب تحديد نوع泛تاتي.
على سبيل المثال، انظر إلى البروتوكول الشامل الذي يستخدم كلاً من int وstring كمعلمات.
public delegate T add<T>(T param1, T param2); // بروتوكول泛تاتي class Program { static void Main(string[] args) { add<int> sum = Sum; Console.WriteLine(sum(10, 20)); add<string> con = Concat; Console.WriteLine(conct("Hello", "World!!")); {} public static int Sum(int val1, int val2) { return val1 + val2; {} public static string Concat(string str1, string str2) { return str1 + str2; {} {}
يستخدم البروتوكول أيضًا لبيان الأحداث والوظائف الغير معروفة.
البروتوكول هو نوع بيانات مرجعي يعرف ببروتوكول التوقيع.
يمكن للواحد من أن يشير إلى أي دالة لها نفس التوقيع كما هو الحال في البروتوكول.
الجملة النصية:[الوصلة الديناميكية] بروتوكول [نوع العودة] [اسم البروتوكول]([المتغيرات])
يجب أن تتطابق توقيع الطريقة المستهدفة مع توقيع الوكيل.
يمكن طلب الوكيل مثل الطريقة العادية أو invoke().
يمكنك استخدام عمليات إضافة (+) أو (+ =) لتخصيص عدة طرق إلى الوكيل، واستخدام عمليات الحذف (-) أو (- =) لإزالتها. إنه يُدعى الوكيل المتعدد.
إذا عاد الوكيل المتعدد القيمة، فإنه يعود القيمة من الطريقة الأخيرة التي تم تخصيصها.
يستخدم الوكيل لتحديد الأحداث والطرق المجهولة في C#.