الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Delegate in .Net , Part 1

بدأه AliBazzi في 21 سبتمبر 2010 · 2 رد · 1,487 مشاهدة · في قسم تكنولوجيا Microsoft .NET العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

Delegate أو المندوب ما هو إلا Object يقوم بحفظ عنوان Method معينة , ليتم إستعمال هذا الـ Object الذي يحتفظ بمؤشر إلى تلك الـ Method في تنفيذها عند الحاجة من قبل مستعمل الـ Delegate .

فلنأخذ المثال التالي , لنفهم الحاجة لوجود بنية كهذه :

Smart Printer يقدم خدمة طباعة قيمة أي تابع رياضي يأخذ قيمة int ويعيد قيمة Double ,ويقوم الـ Smart Printer بطباعة النتيجة و إسم التابع بطريقة أنيقة إلى الـ Console , فلنلقي نظرة إلى الشكل التالي :

ClassDiagram1.png

فكما هو ملاحظ من الشكل السابق , الـ Smart Printer يظهر كمقدم خدمة (ألا و هي الطباعة إلى الـ Console ) إلى كل Object يحتاج إلى هذه الخدمة ,ولكي يٌخدَم اي Object من قبل الـ Smart Printer فإنه يحتاج إلى تطبيق الواجهة : ISmartPrint التي تحوي الـ Members التالية :

Calculate : سيقوم الـ Smart Printer بطلب هذه الـ Method التي ستحوي function لا يعرف محتواها مسبقا الـ Smart Printer , لكن ما يعرفه عنها يكفيه لتقديم الخدمة لها , فهو يعرف أنها تأخذ int وتعيد Double ...

Parameter : وهو الرقم الذي سيقوم بتمريرة الـ Smart Printer عند حساب قيمة الـ Function عند تلك القيمة ...

Name : و هو إسم الـ Function الرياضي الذي سيقوم الـ Printer بعرضه عند تقديم الخدمة لذلك التابع الرياضي (في عرضه بشكل جميل على الـ Console ) .

حاليا , لدينا زبونان يحتاجان إلى خدمة العرض و التنسيق الجميل على شاشة الـ Console ... إنهما التابعين الرياضيين : Factorial , Fibonacci وهما متمثلان في الـ Factorial , Fibonacci Class الذين يطبقان الـ ISmartPrint Interface كأحد شروط التخديم ...

فلنستعرض الكود الاّن :

public interface ISmartPrint
    {
         string Name { get; }
        int Parameter { get; }
         double Calculate(int num);
    }

والزبائن هما :

public class Fibonacci : ISmartPrint
    {
         public string Name
        {
            get { return  "Fibonacci Function"; }
        }

        public int Parameter  
        { 
            get { return 10; } 
        }

         public double Calculate(int num)
        {
            if  (num <= 1)
            {
                return 1;
             }
            return Calculate(num - 1) + Calculate(num - 2);
         }
    }

public  class Factorial : ISmartPrint
    {
        public string Name
         {
            get { return "Factorial Function"; }
        }

         public int Parameter 
        {
            get { return  16; } 
        }

        public double Calculate(int num)
         {
            if (num <=1)
            {
                 return 1;
            }
            return num * Calculate(num -  1);
        }
    }

وأما مقدم الخدمة فهو :

public class SmartPrinter
    {

         public SmartPrinter(ISmartPrint smartPrint)
        {
             this.SmartPrint = smartPrint;
        }

        public  ISmartPrint SmartPrint { get; set; }

        public void Print()
         {
            Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("calculating {0} ...",SmartPrint.Name);
             Console.ForegroundColor = ConsoleColor.Red;
             Console.WriteLine("The Value of {0} with parameter : {1} is  {2}",SmartPrint.Name,SmartPrint.Parameter,SmartPrint.Calculate(SmartPrint.Parameter));
             Console.ForegroundColor = ConsoleColor.Gray;
        }
     }

يقوم الـ Smart Printer بتلقي الـ Object المراد خدمته عبر الـ Constructor الخاص به , وعند إستدعاء Print يقوم بحساب قيمة التابع عبر تمرير الـ Parameter الموجود في نفس الـ Object المٌخدم ... ولكن بالتأكيد عرضه للمعلومات التي حصل عليها , سيحوي الكثير من البهرجة البصرية في شاشة Console تعيسة icon_e_wink.gif ...

كود الإختبار :

SmartPrinter printer = new SmartPrinter(new  Factorial());
            printer.Print();

             Console.WriteLine("\nChanging the Smart Object...\n");

             printer.SmartPrint = new Fibonacci();
            printer.Print();

             Console.ReadLine();

ستظهر النتيجة كالاّتي :

calculating Factorial Function ...

The Value of Factorial Function with parameter : 16 is 20922789888000

Changing the Smart Object...

calculating Fibonacci Function ...

The Value of Fibonacci Function with parameter : 10 is 89

لكن مع بعض الألوان ...

رغم بساطة السيناريو , لكن لا بد من إعادة التلخيص بالأفكار التالية :

الـ Smart Printer قدم خدمة لزبائنة Fibonacci , Factorial الذين بدورهم إحتاجا لمن يقوم بعرض نتائجهم بطريقة جيدة ...

والاّن , فلننتقل لدراسة البُنى الجاهزة الموجودة في الـ .Net والمتمثلة بالكلمة المفتاحية Delegate ,فلنقم بتقديم الحل السابق ولكن بالحل الجديد المختصر :

public delegate double Func(int num); // here is  the magic
    class Program
    {
        static void  Main(string[] args)
        {
            SmartPrinter printer =  new SmartPrinter(new Func(Factorial), 11, "Factorial");
             printer.Print();

            Console.WriteLine("\nChanging the  Smart Object...\n");

            printer.Function = new  Func(fibonacci);
            printer.Name = "Fibonacci";
             printer.Parameter = 6;

            printer.Print();

         }

        private static double Factorial(int number)
         {
            if (number <= 1)
            {
                 return 1;
            }
            return number *  Factorial(number - 1);
        }

        private static double  fibonacci(int number)
        {
            if (number <= 1)
             {
                return 1;
            }
             return fibonacci(number - 1) + fibonacci(number - 2);
        }
     }

وبالتأكيد سيتم تعديل الـ Smart Printer ايضا :

public class SmartPrinter
    {
         public SmartPrinter(Func function, int parameter, string name)
         {
            this.Function = function;
             this.Parameter = parameter;
            this.Name = name;
        }

         public string Name { get; set; }

        public int  Parameter { get; set; }

        public Func Function { get; set; }

         public void Print()
        {
             Console.ForegroundColor = ConsoleColor.Green;
             Console.WriteLine("calculating {0} ...", this.Name);
             Console.ForegroundColor = ConsoleColor.Red;
             Console.WriteLine("The Value of {0} with parameter : {1} is {2}",  this.Name, this.Parameter, this.Function.Invoke(Parameter));
             Console.ForegroundColor = ConsoleColor.Gray;
        }
    }

ما يجب ملاحظته هنا هو أننا قمنا بإلغاء فكرة أن الزبون يجب أن يتمثل في Object , بل قمنا بالإستغناء عن ذلك و عوضا عنه , قمنا بتمرير ثلاث معلومات أساسية إلى الـ Smart Printer هم : Function , Parameter ,Name وهم نفس الأعضاء الذين تواجدوا في الـ IsmartPrinter Interface التي تم الإستغناء عنها , الجميل هنا أننا إستطعنا تمرير إسم Function إلى الـ Smart Printer عن طريق الـ Func Delegate الذي تم تعريفة في السطر الأول كما يلي :

public delegate double Func(int num);

والذي يعبر عن مندوب يستطيع حمل إسم أي Method تحمل نفس توقيعه (أي الـ Parameters والـ Return Type ) , فقط نعامله على أنه Type عادي قابل للـ Instantiation (الإستمثال , فلنعد إلى الإنكليزية أفضل icon_e_wink.gif ) ...

فنستيطع عمل شيء كالتالي :

private static double Factorial(int number)
         {
            if (number <= 1)
            {
                 return 1;
            }
            return number *  Factorial(number - 1);
        }
static void main() {
Func  factorial = new Func(Factorial);
            SmartPrinter printer =  new SmartPrinter(factorial,11,"Facotiral");
             printer.Print();
{

فنلاحظ أننا قمنا بإستعمل الـ Func Delegate كأي Type و قمنا بالتأشير في الـ Constructor الخاص به إلى الـ Factorial Method ...

أكبر خطأ شائع عند إستعمال الـ Delegate هو إستدعاء الـ Method عند تمريرها , بدل تمرير إسمها فقط , فلم نقم في المثال السابق بكتابة شيء كالتالي :

Func  factorial = new Func(Factorial()); // Will not compile ...

فكرة أخرى , لو لم يكن الـ Delegate بالحقيقة Type لما أمكن وضعه بمكان لا يتم فيه إلا تعريف Types , وللحقيقة هناك معلومة يجب ذكرها ,فالـ Delegate هو Class يرث من MultiCast Delegate Abstract Class , وبالتالي الـ #Compiler of C سيقوم بتوليد هذا الصنف من أجلنا ... ولا نستطيع مشاهدة هذه الحقيقة إلا بأدوات الـ Decompiling كالـ Reflector ...

طريقة إستدعائنا للـ Delegate في الامثلة السابقة تم بشيء يشبه التالي :

Delegate void MyDel(int num);
static void foo(int  n){...}
static void main()
{
    MyDel del = new MyDel(foo);
     del();
}

لكن , بما أن أي Delegate ما هو إلا Type قام الـ Compiler بإنشائه لنا , فنتوقع أن يحوي Members بالتأكيد , وأهم Member يهمنا هو Invoke الذي تعني إستدعاء أو مناشدة , فهي من تقوم بتنفيذ الـ Method الذي يؤشر لها الـ Delegate ...

فنستطيع كتابة شيء كالتالي :

del.Invoke(9);

وعمليا الـ Compiler سيقوم بتبديل كل (del(9 بـ (del.inovke(9 ...

بقية الـ Members ربما يتم التطرق لها في مقالات لاحقة ...

نلاحظ أن هناك الكثير من السهولة التي قدمت لنا عن طريق إستعمال Delegate فلم نعد بحاجة لعمل Interface لتقوم بدور العقد الذي يجب أن يحترمه الطرفان , فإستعضنا عنها بالـ Delegate Construct , والتي مكنتنا أيضا من كتابة فقط الـ Functions بشكل مباشر مثل الـ Factorial , Fibonacci اللتان إحتجنا إلى تغليفهما في Types كما في الحل الأول ... فكلما إستطعنا التخلص من المظاهر الرسمية ,إستطعنا التركير أكثر ...

إلى اللقاء في شرح الـ Anonymous Delegates و Lambda Expressions ...

لكن الأسئلة مباحة ... icon_e_wink.gif

#2

أشكرك أستاذي

قرأت من عدة أيام عن Delegate

من مكتبة ميكروسفت MSDN

ومن خلال دروسك الثلاثة شكلت لي أضافة

والمقارنة التقيلدية مع Delegate و EVENT

وقد ذكرت في مشاركتك

اقتباس

وجهان لعملة واحدة , هي عملة الـ Delegate فالـ Event هو delegate ليس إلا بميزة واحدة فقط :

عندما تقوم بالربط مع حدث , فلا تستطيع إلا عمل Attach , De attach وبالتالي يقوم يقوم الـ event بحماية مراقبيه (الـ observer ), بمعنى اّخر لا يستطيع أحد أن يحذف كافة مراقبي الحدث , بالأحرى لا يمكن تنفيذ الكود التالي :

expand plain text

Button1.click=new EventHandler<MouseClick>(click_handler);

بل أنت مجبر على إستعمال فقط الـ =+ و =- , أي :

expand plain text

Button1.click+=new EventHandler<MouseClick>(click_handler);

وهما الربط و فك الربط على الترتيب , وهذا سلوك منطقي للغاية ...

أتمنى أن تكون لأمور قد وضحت

سأحرص على قرأت هذا الكتاب الذي أشرت أليه

Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries

تعلم فليس المرء يولد عالماً------ وليس أخو علماً كمن هو جاهلا

العلم نور وجمال يقتبس--------------- صاحبه مكرم اين ما جلس

من فاته العلم ساعة تظعظع ونتكس----شتان شتان بين حمار وفرس

#3

أهلا بك أخي الكريم , يسعدني سماع ذلك ...

ربما تحب أن تقرأ : Observer Pattern

تم تعديل هذه المشاركة بواسطة AliBazzi في 24 سبتمبر 2010 في 22:22

مواضيع مشابهة