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

الاضافات في سي#2 - Anonymous Methods

مغلق
بدأه هاني الأتاسي في 3 أكتوبر 2005 · 5 رد · 1,530 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

Anonymous Methods

هذه الميزة قد تتيح تسهيلات كثيرة للمبرمجين عند تعاملهم مع ال Delegates . في السي# استخدام الdelegate قد يكون غريبا قليلا عن استخدام التوابع في سي++ . ففي السي++ إذا أردت تمرير مؤشر التابع إلى تابع ما تقوم فقط بكتابة اسم التابع . أما في السي# يجب عليك أن تنشئ كائن جديد delegate يحتوي التابع الذي تريد تمريره .

في الاصدار الجديد من سي# تمت تحسين هذه الطريقة في تمرير التوابع ، والآن بدلا من أن تنشئ delegate خاص يمكنك فقط كتابة اسم التابع تماما كما في سي++ :

// في سي# القديمة
button1.Click += new EventHandler(button1_Click);

// في سي# الاصدار الجديد
button1.Click += button1_Click

والمثال التالي يوضح كيف يمكن تمرير اسم التابع فقط لتابع آخر بدلا من انشاء delegate خاص:

class Program {
	static void Main() {
  ThreadPool.QueueUserWorkItem(MyCallbackFunction, 10);
	}

	static void MyCallbackFunction(object o) {
  Console.WriteLine(o);
	}
}

بالاضافة إلى كل السابق فتم اضافة تسهيلات جديدة في سي# الاصدار الثاني وهي تشابه ميزات موجودة في JavaScript ولكن أفضل بكثير. حيث يمكنك أن تكتب التابع Callback Function مباشرة أثناء تمريره بدلا من تعريف تابع منفصل .

    class Program
    {
        static void Main(string[] args)
        {
            System.Threading.Timer timer = new System.Threading.Timer(
                delegate(Object obj) { MessageBox.Show("Hello :)"); }, 10, 1000, 1000);

            Console.ReadLine();
        }
    }

لاحظ كيف قمنا بكتابة الكود الذي يظهر الرسالة Hello مباشرة أثناء انشائنا للTimer . الكود السابق سوف يظهر الرسالة Hello كل ثانية حتى يتم انهاء البرنامج.

الآن إذا حاولنا رؤية الassembly الناتجة لمعرفة ماذا فعل المترجم للكود الذي كتبناه لنجد أن المترجم قد أنشئ تابع جديد وقام باضافة كود جديد داخل التابع Main (استخدت أداة Lutz Roeder's .NET Reflector من هنا http://www.aisto.com/roeder/dotnet/)

class Program {

  private static void Main(string[] args)
  {
      if (Program.<>9__CachedAnonymousMethodDelegate1 == null)
      {
            Program.<>9__CachedAnonymousMethodDelegate1 = new TimerCallback(Program.<Main>b__0);
      }
      Timer timer1 = new Timer(Program.<>9__CachedAnonymousMethodDelegate1, 10, 0x3e8, 0x3e8);
      Console.ReadLine();
  }

  private static void <Main>b__0(object obj)
  {
      MessageBox.Show("Hello :)");
  }

  private static TimerCallback <>9__CachedAnonymousMethodDelegate1;

}

لاحظ أنه تم تعريف متحول من نوع TimerCallback وهو static واسمه <>9__CachedAnonymousMethodDelegate1 . إذا لاحظنا داخل Main فإن هذا المتحول سوف يحتوي على الكائن الذي يحوي مؤشر إلى التابع الجديد الذي انتجه المترجم . هذا التابع اسمه <Main>b__0 وهو يحتوي الكود الذي كتبناه أصلا .

بالمختصر فإن العملية ليست معقدة كثيرا حتى الآن ، فالمترجم يقوم وراء الكوليس بعمل كل هذه الأمور بشكل آلي . لاحظ أنه لا توجد اي مشكلة إذا حاولنا من داخل الanonymous method الوصول إلى متحولات معرفة داخل الكلاس لأن التابع الجديد الذي أنشئه المترجم هو أساسا داخل الكلاس. انظر المثال:

    class Program
    {
        static int counter = 0;

        static void Main(string[] args)
        {
            Timer timer = new Timer(
                delegate(Object obj) { Console.WriteLine(counter++); }, 10, 1000, 1000);

            Console.ReadLine();
        }
    }

تنفيد البرنامج السباق سوف يظهر الأرقام 0 ، 1 ، 2 ، 3 ، 4 ، ....

أحب أن أذكر أيضا أنه ليس من الداعي ذكر البارامترات عند كتابتك لل anonymous method إذا لم تكن تستخدمهم من الداخل . على سبيل المثال يمكن كتابة الكود السابق كالتالي:

    class Program
    {
        static int counter = 0;

        static void Main(string[] args)
        {
            Timer timer = new Timer(
                delegate { Console.WriteLine(counter++); }, 10, 1000, 1000);

            Console.ReadLine();
        }
    }

الآن ، ماذا لو فكرنا قليلا وحاولنا الوصول إلى متحولات معرفة ضمن التابع الأساسي من داخل الanonymous method .. كما رئينا سابقا فإن التابع الذي ينشئه المترجم هو تابع منفصل عن التابع الأساسي ، فكيف يمكن الوصول إلى المتحولات المعرفة داخل التابع الأساسي!؟ .. انظر المثال التالي:

    class Program
    {
        static void StartTimer()
        {
            int counter = 0;

            Timer timer1 = new Timer(
                delegate { Console.WriteLine("Timer1 = {0}", counter++); }, 10, 1000, 1000);
        }

        static void Main(string[] args)
        {
            StartTimer();

            Console.ReadLine();
        }
    }

نتيجة تنفيذ البرنامج السابق هي:

0

1

2

وهكذا ...

لاحظ أنه قمنا باستخدام المتحول الداخلي counter من ضمن ال anonymous method . وبعد اشائنا للمؤقت فإننا نخرج من التابع مباشرة ، ونرجع إلى التابع Main . ولكن ال counter هي عبارة عن متحول تم انشائه في ال stack ويتم حذفه مباشرة عند الخروج من التابع StartTimer . ولكن كيف عمل البرنامج بصورة صحيحة؟! وكأن المتحول counter مازال على قيد الحياة .

لو نظرنا إلى الكود المنتج من المثال السابق داخل الأداة .NET Reflecotr ، لوجدنا أن المترجم قال بعمل اضافي هنا، انظر إلى الكود الجديد الذي أنتجه المترجم:

class Program 
{
  private static void Main(string[] args) {
      Program.StartTimer();
      Console.ReadLine();
  }

  private static void StartTimer() {
      Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1();
      class1.counter = 0;
      Timer timer1 = new Timer(new TimerCallback(class1.<StartTimer>b__0), 10, 0x3e8, 0x3e8);
  }

  private sealed class <>c__DisplayClass1 {
      // Methods
      public <>c__DisplayClass1() {}
      public void <StartTimer>b__0(object) {
          Console.WriteLine("Timer1 = {0}", this.counter++);
      }

      // Fields
      public int counter;
  }
}

المترجم قام باضافة كلاس جديد يحتوي على الanonymous method الذي قمنا بكتابته بالاضافة إلى متحول counter . لاحظ داخل التابع StartTimer فإنه تم انشاء هذا الكلاس الجديد واسناد قيمة للمتحول counter ومن ثم استخدام التابع عندم انشاء المؤقت .. أي بالمختصر فإن المترجم قام بعمل كلاس جديد لتغليف المتحولات التي تم تعريفها داخل التابع الأساسي.

جميل جدا بأن تتيح سي# تسهيلات عديدة في استخدام ال Anonymous Method . ولكن كنصيحة مني يفضل أن لا يزيد تابع ال anonymous method عن ثلاث أسطر!! لإن كثرة استخدامها وخصوصا إذا كان التابع كبير قد يجعل من مراجعة وتنقيح البرنامج صعبا جدا .

>> انتهى <<

تم تعديل هذه المشاركة بواسطة هاني الأتاسي في 3 أكتوبر 2005 في 03:39

Coding on the Cloud and for the Cloud!

My Blog

#2

كمثال رائع على استخدام ال anonymous method واجهني اليوم هو استخدامها مع التابع Regex.Replace في حالة استخدام callback function معها .. ففي السابق كنت اعرف تابع منفصل من أجلها أما الآن فيمكن أن اكتب التابع مباشرة عند استدعاء Replace .

Coding on the Cloud and for the Cloud!

My Blog

#3

شكرا أخ هاني على مواضيعك المتميزه.

Anonymous Methods اضافه جميله جدا للسي شارب ... وتعجبني جدا خصوصا عند استخدام الـ Events , بالرغم من أن الـ Visual Studio كانت تقوم بكتابة لنا الكثير من الكود عند الضغط على زرار TAB :).

أحببت أن أضع مثال عن الـ Events اذا أردنا التعامل مع الـ sender و الـ e داخل الـ Event Handler عند استخدام الـ Anonymous Methods ::

الأمر كأننا بالفعل نقوم بكتابة Event Handler ولكن بدون اسم ولهذا أعتقد سبب أنهم أطلقوا عليها Anonymous ::

TextBox myTB = new TextBox();
myTB.KeyPress += delegate(object sender, KeyPressEventArgs e)
{
MessageBox.Show("You pressed "+ e.KeyChar.ToString());
};

لاحظ الـ SemiColon الموجوده بعد القوس الأخير :D

تم تعديل هذه المشاركة بواسطة معتز شمس في 4 أكتوبر 2005 في 12:42

#Read

http://MoutazShams.blogspot.com

projects003.gif

أعتذر عن التغيب هذه الأيام نظرا للانشغال المريب

#4

كان من أهم أسباب عدم رضاي عن سي شارب هو عدم وجود Anonymous Interfaces وكان أكبر نقص فيها، ولكنها الآن موجودة في الإصدار الثاني بأسلوب Anonymous Delegates.

الآن البرمجة أصبحت ممتعة!

#5

هل ممكن من المشرفين تثبيت هذا الموضوع أو نسخه إلى الصفحة الرئيسية في الموقع ؟

Coding on the Cloud and for the Cloud!

My Blog

#6
اقتباس
هل ممكن من المشرفين تثبيت هذا الموضوع أو نسخه إلى الصفحة الرئيسية في الموقع ؟
أنا عن نفسي أردت أن أقوم بتثبيت كل المواضيع التي تتحدث عن الاضافات في سي شارب 2 ... ولكن بذلك سيصبح هناك الكثير من المواضيع المثبته , لذلك قمت بعمل موضوع يحتوي على جميع الروابط التي تتحدث عنها منذ فتره باسم " حضر نفسك من هنا للانتقال الى سي شارب 2 " وهو موضوع مثبت ولكني لم أنته منه بعد بالعلم من أنني لم أغلقه حتى يستطيع الجميع الاضافه فيه.

أعتقد أن هذا أفضل من تثبيت أكثر من 4 مواضيع.

تم تعديل هذه المشاركة بواسطة معتز شمس في 9 أكتوبر 2005 في 04:48

#Read

http://MoutazShams.blogspot.com

projects003.gif

أعتذر عن التغيب هذه الأيام نظرا للانشغال المريب

هذا الموضوع مغلق.

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