سؤال

لقد قرأت بسرعة على تعبير Microsoft Lambda توثيق.

ساعدني هذا النوع من الأمثلة على فهم أفضل ، على الرغم من ذلك:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

ومع ذلك ، لا أفهم لماذا هذا الابتكار. إنها مجرد طريقة تموت عندما ينتهي متغير الطريقة "، أليس كذلك؟ لماذا يجب أن أستخدم هذا بدلاً من طريقة حقيقية؟

هل كانت مفيدة؟

المحلول

تعبيرات لامدا هي بناء جملة أبسط للمندوبين المجهولين ويمكن استخدامه في كل مكان يمكن استخدام مندوب مجهول. ومع ذلك ، فإن العكس غير صحيح ؛ يمكن تحويل تعبيرات Lambda إلى أشجار التعبير التي تسمح بالكثير من السحر مثل LINQ إلى SQL.

فيما يلي مثال على أ LINQ إلى الأشياء التعبير باستخدام مندوبين مجهولين ثم تعبيرات Lambda لإظهار مدى أسهل في العين:

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

تعبيرات Lambda والمندوبين المجهولين لها ميزة في كتابة وظيفة منفصلة: إنها تنفذ الإغلاق الذي يمكن أن يسمح لك بذلك تمرير الحالة المحلية إلى الوظيفة دون إضافة معلمات إلى الوظيفة أو إنشاء كائنات الاستخدام لمرة واحدة.

أشجار التعبير هي ميزة جديدة قوية جدًا لـ C# 3.0 تسمح لـ API بالنظر إلى بنية التعبير بدلاً من مجرد الحصول على إشارة إلى طريقة يمكن تنفيذها. يجب على واجهة برمجة التطبيقات فقط جعل معلمة مندوب في Expression<T> ستقوم المعلمة والمترجم بشجرة تعبير من Lambda بدلاً من مندوب مجهول:

void Example(Predicate<int> aDelegate);

يسمى مثل:

Example(x => x > 5);

يصبح:

void Example(Expression<Predicate<int>> expressionTree);

سيتم تمرير هذا الأخير تمثيل مجردة شجرة بناء الجملة الذي يصف التعبير x > 5. تعتمد LINQ TO SQL على هذا السلوك لتكون قادرة على تحويل تعبيرات C# إلى تعبيرات SQL المطلوبة للتصفية / الطلب / وما إلى ذلك على جانب الخادم.

نصائح أخرى

تعتبر الوظائف والتعبيرات المجهولة مفيدة لطرق لمرة واحدة لا تستفيد من العمل الإضافي المطلوب لإنشاء طريقة كاملة.

النظر في هذا المثال:

 string person = people.Find(person => person.Contains("Joe"));

عكس

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

هذه مكافئة وظيفيا.

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

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

بفضل تعبيرات Lambda ، يمكنك استخدامها مثل هذا:

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

أسهل بكثير.

تم تنظيف Lambda's Clean Up C# 2.0 Syntax المجهول ... على سبيل المثال

Strings.Find(s => s == "hello");

تم في C# 2.0 مثل هذا:

Strings.Find(delegate(String s) { return s == "hello"; });

من الناحية الوظيفية ، يفعلون الشيء نفسه بالضبط ، إنه مجرد بناء جملة أكثر إيجازًا.

هذه مجرد طريقة واحدة لاستخدام تعبير Lambda. يمكنك استخدام تعبير Lambda في أى مكان يمكنك استخدام مندوب. هذا يتيح لك القيام بأشياء مثل هذا:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

سيبحث هذا الرمز في القائمة عن إدخال يطابق كلمة "Hello". الطريقة الأخرى للقيام بذلك هي تمرير مندوب إلى طريقة البحث ، مثل هذا:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

تعديل:

في C# 2.0 ، يمكن القيام بذلك باستخدام بناء جملة مندوب مجهول:

  strings.Find(delegate(String s) { return s == "hello"; });

تم تنظيف Lambda بشكل كبير هذا بناء الجملة.

لقد منحتنا Microsoft طريقة أنظف وأكثر ملاءمة لإنشاء مندوبين مجهولين يسمى تعبيرات Lambda. ومع ذلك ، لا يوجد الكثير من الاهتمام الذي يتم إيلاءه إلى التعبيرات جزء من هذا البيان. أصدرت Microsoft مساحة اسم كاملة ، System.linq.expressions, التي تحتوي على فئات لإنشاء أشجار التعبير على أساس تعبيرات Lambda. تتكون أشجار التعبير من كائنات تمثل المنطق. على سبيل المثال ، x = y + z هو تعبير قد يكون جزءًا من شجرة تعبير في .NET. النظر في مثال بسيط التالية:

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

هذا المثال تافهة. وأنا متأكد من أنك تفكر ، "هذا عديم الفائدة حيث كان بإمكاني إنشاء المندوب مباشرة بدلاً من إنشاء تعبير وتجميعه في وقت التشغيل". وكنت على حق. ولكن هذا يوفر الأساس لأشجار التعبير. هناك عدد من التعبيرات المتوفرة في مساحات أسماء التعبيرات ، ويمكنك إنشاء خاص بك. أعتقد أنه يمكنك رؤية أن هذا قد يكون مفيدًا عندما لا تعرف بالضبط ما الذي يجب أن تكون الخوارزمية في وقت التصميم أو الترجمة. رأيت مثالاً في مكان ما لاستخدام هذا لكتابة آلة حاسبة علمية. يمكنك أيضا استخدامه ل بايزي الأنظمة ، أو ل البرمجة الوراثية (AI). عدة مرات في حياتي المهنية ، كان عليّ أن أكتب وظائف تشبه Excel والتي سمحت للمستخدمين بإدخال تعبيرات بسيطة (الإضافة ، الفرعية ، إلخ) للعمل على البيانات المتاحة. في Pre.net 3.5 ، اضطررت إلى اللجوء إلى بعض لغة البرمجة النصية الخارجية إلى C#، أو اضطررت إلى استخدام وظيفة الانبعاثات في الكود في الانعكاس لإنشاء رمز .NET أثناء الطيران. الآن أود استخدام أشجار التعبير.

يوفر الحاجة إلى وجود طرق تستخدم مرة واحدة فقط في مكان معين من التعريف بعيدًا عن المكان الذي يتم استخدامه فيه. الاستخدامات الجيدة هي كمقارنات للخوارزميات العامة مثل الفرز ، حيث يمكنك بعد ذلك تحديد وظيفة الفرز المخصصة حيث تستدعي هذا النوع بدلاً من إجبارك على البحث في مكان آخر لمعرفة ما تقوم بفرزه.

وهذا ليس حقًا ابتكارًا. كان Lisp وظائف Lambda لمدة 30 عامًا أو أكثر.

تعبير Lambda يشبه طريقة مجهولة المكتوبة بدلاً من مثيل مندوب.

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

النظر في تعبير لامدا x => x * x;

قيمة معلمة الإدخال هي x (على الجانب الأيسر من =>)

منطق الوظيفة هو x * x (على الجانب الأيمن من =>)

يمكن أن يكون رمز تعبير Lambda عبارة عن كتلة عبارة بدلاً من التعبير.

x => {return x * x;};

مثال

ملحوظة: Func هو مندوب عام محدد مسبقا.

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

مراجع

  1. كيف يمكن استخدام مندوب وواجهة بالتبادل؟

يمكنك أيضًا العثور على استخدام تعبيرات Lambda في كتابة رموز عامة للعمل على أساليبك.

على سبيل المثال: وظيفة عامة لحساب الوقت المستغرق بواسطة استدعاء الطريقة. (بمعنى آخر Action هنا)

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

ويمكنك استدعاء الطريقة أعلاه باستخدام تعبير Lambda على النحو التالي ،

var timeTaken = Measure(() => yourMethod(param));

يتيح لك التعبير الحصول على قيمة الإرجاع من طريقتك و Out Param أيضًا

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));

في كثير من الأحيان ، لا تستخدم الوظيفة في مكان واحد فقط ، لذا فإن جعل طريقة ما يرفع في الفصل.

تعبير Lambda هو وسيلة موجزة لتمثيل طريقة مجهولة. تتيح لك كل من الأساليب المجهولة وتعبيرات Lambda تحديد تنفيذ الطريقة المضمّنة ، ومع ذلك ، فإن طريقة مجهولة المصدر تتطلب منك صراحة تحديد أنواع المعلمات ونوع الإرجاع للطريقة. يستخدم تعبير Lambda ميزة الاستدلال النوع لـ C# 3.0 والذي يسمح للمترجم باستنتاج نوع المتغير استنادًا إلى السياق. إنه مريح للغاية لأن ذلك يوفر لنا الكثير من الكتابة!

إنها وسيلة لأخذ عملية صغيرة ووضعها بالقرب من المكان الذي يتم استخدامه (على عكس إعلان متغير قريب من نقطة الاستخدام). من المفترض أن يجعل هذا الكود أكثر قابلية للقراءة. من خلال إخفاء الهوية التعبير ، فإنك تجعل من الصعب أيضًا على شخص ما كسر رمز العميل الخاص بك إذا تم استخدام الوظيفة في مكان آخر وتعديلها "إلى" تعزيز ".

وبالمثل ، لماذا تحتاج إلى استخدام Foreach؟ يمكنك أن تفعل كل شيء في Foreach مع سهل للحلقة أو مجرد استخدام ienumerable مباشرة. الإجابة: أنت لا تفعل بحاجة إلى لكنه يجعل الكود الخاص بك أكثر قابلية للقراءة.

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

على سبيل المثال ، قبل أن تكون قد استخدمت SQL ويمكن أن تحصل على هجوم حقن SQL ، لأن المتسلل مر بسلسلة حيث كان من المتوقع عادةً رقمًا. الآن يمكنك استخدام تعبير LINQ Lambda ، وهو محمي من ذلك.

لا يمكن بناء واجهة برمجة تطبيقات LINQ على المندوبين النقيين ، لأنه يتطلب الجمع بين أشجار التعبير معًا قبل تقييمها.

في عام 2016 ، معظم اللغات الشعبية لديها تعبير لامدا كان الدعم ، و C# أحد رواد هذا التطور بين اللغات الضرورية السائدة.

ربما يكون هذا هو أفضل تفسيرات حول سبب استخدام تعبيرات Lambda -> https://youtu.be/j9nj5dto54q

باختصار ، هو تحسين قابلية قراءة التعليمات البرمجية ، وتقليل فرص الأخطاء عن طريق إعادة استخدام التعليمات البرمجية بدلاً من تكرارها ، والاستفادة من التحسين الذي يحدث وراء الكواليس.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top