English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# 基础教程

C# 高级教程

C# 面向对象(OOP)

الوكيل في C#

如果我们要将函数作为参数传递怎么办?C#如何处理回调函数或事件处理程序?答案是-委托(delegate)。委托(Delegate) 是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。

المعامل هوتحديد إشارة الطريقةنوع البيانات المفردة للمراجع. يمكنك تعريف متغيرات المعامل، مثل أي نوع بيانات آخر، يمكن أن تشير إلى أي طريقة لها نفس إشارة المعامل.

عمل المعامل يتضمن ثلاث خطوات:

  1. إعلان المعامل

  2. تعيين الطريقة المستهدفة

  3. استدعاء المعامل

يمكن استخدام كلمة المفتاح delegate وخطوة التوقيع للمعاملات لإعلان المعاملات، مثلما هو موضح أدناه.

  جملة المعامل

[modifier of access] delegate [return type] [name of delegate]([parameters])

إليك إعلانًا للمعامل باسم MyDelegate.

public delegate void MyDelegate(string msg);

في الأعلى، تم إعلان MyDelegate يحتوي علىvoidنوع العودة والمعامل النصي. يمكن إعلان المعامل في الخارج أو داخل الكائن. في الواقع، يجب إعلانه في الخارج.

بعد إعلان المعامل، نحتاج إلى تعيين الطريقة المستهدفة أو تعبير 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);
    {}
{}

الشكل التالي يوضح المعاملات.

مكتبات C# المعاملات

إرسال المعاملات كمعامل

الطريقة يمكن أن تحتوي على معاملات نوع الالتزام، مثلما هو موضح أدناه.

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;
    {}
{}

يستخدم البروتوكول أيضًا لبيان الأحداث والوظائف الغير معروفة.

 نقاط يجب تذكرها

  1. البروتوكول هو نوع بيانات مرجعي يعرف ببروتوكول التوقيع.

  2. يمكن للواحد من أن يشير إلى أي دالة لها نفس التوقيع كما هو الحال في البروتوكول.

  3. الجملة النصية:[الوصلة الديناميكية] بروتوكول [نوع العودة] [اسم البروتوكول]([المتغيرات])

  4. يجب أن تتطابق توقيع الطريقة المستهدفة مع توقيع الوكيل.

  5. يمكن طلب الوكيل مثل الطريقة العادية أو invoke().

  6. يمكنك استخدام عمليات إضافة (+) أو (+ =) لتخصيص عدة طرق إلى الوكيل، واستخدام عمليات الحذف (-) أو (- =) لإزالتها. إنه يُدعى الوكيل المتعدد.

  7. إذا عاد الوكيل المتعدد القيمة، فإنه يعود القيمة من الطريقة الأخيرة التي تم تخصيصها.

  8. يستخدم الوكيل لتحديد الأحداث والطرق المجهولة في C#.