تعبيرات لامدا (ارشادات برمجة C#)
تعبير لامدا هي دالة مجهولة يمكن أن تحتوي على تعبيرات وعبارات, ولا يمكن استخدامها لإنشاء مفوضين أو أنواع تعبير الشجرة.
جميع تعبيرات لامدا تستخدم عامل تشغيل لامدا => ، الذي يتم قراءته كـ "الانتقال إلى". الجانب الأيسر من عامل لامدا تعيين معلمات الإدخال (أن وجدت) ويحمل الجانب الأيمن التعبير أو بيان الكتلة. تعبير لامدا x => x * x يقرأ "x ينتقل إلى x مرات x." يمكن تعيين هذا التعبير إلى نوع تفويض كالتالي:
delegate int del(int i);
static void Main(string[] args)
{
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
}
لإنشاء تعبير نوع الشجرة:
using System.Linq.Expressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Expression<del> myET = x => x * x;
}
}
}
عامل التشغيل => له نفس الأسبقيةكالتعيين =) و هو اقتران لليمين.
يتم استخدام lambdas في الأسلوب المبني لاستعلاماتLINQ كوسائط لأساليب مشغل الاستعلام القياسي مثل Where.
عند استخدام أسلوب المبني على بناء لاستدعاء أسلوب Where في فئة Enumerable (كما هو الحال في الفئة LINQ للكائنات و مكون LINQ to XML) فإن المعلمة هي نوع تفويض System.Func<T, TResult>. تعبير لامدا هو الطريقة الأكثر مناسبة لإنشاء تفويض. على سبيل المثال, عند استدعاء نفس الأسلوب، فإن الفئة System.Linq.Queryable (كما هو الحال في مكون LINQ to SQL) ثم يكون نوع المعلمة <Func> System.Linq.Expressions.Expressionحيث Func هي أي تفويضات Func مع معلمات إدخال أكثر حتى ستة عشر. ومرة أخرى، تعبير لامدا هو طريقة موجزة جداً لبناء تعبير الشجرة ذاك. تسمح lambdas للاستدعاءات Where لن تكون متشابهة على الرغم من حقيقة أن نوع الكائن تم إنشاؤه من لامدا يكون مختلفاً.
في المثال السابق، لاحظ أن توقيع التفويض يحتوي على معلمة إدخال من نوع مضمن ضمنيًا من نوع int، ويرجع int. يمكن تحويل تعبير لامدا إلى تفويض من ذلك النوع لأنه أيضاً يملك معلمة إدخال واحدة (x) و قيمة إرجاع يمكن للمحول البرمجي تحويلها ضمنياً لنوع int. ( تمت مناقشة نوع الواجهة بتفصيل أكثر في الأقسام التالية. ) عند استدعاء التفويض باستخدام معلمة الإدخال 5 فإنه يرجع كنتيجة 25.
لا يسمح للأساليب المجهولة أن تكون على الجانب الأيسر من عامل التشغيل is.
الكل القيود المطبقة على الأساليب المجهولة تنطبق أيضاً على تعبيرات لامدا. لمزيد من المعلومات، راجع الأساليب المجهولة (دليل البرمجة لـ #C).
تعبير لامدا
تعبير لامدا مع التعبير على الجانب الأيمن يسمى تعبير لامدا. تعبير لامدا يتم استخدامها بشكل مكثف في الدوال الإنشائية أشجار التعبير (C# و Visual Basic). يرجع تعبير لامدا نتيجة للتعبير ثم يأخذ النموذج الأساسي التالي:
(input parameters) => expression
الأقواس اختيارية فقط إذا كان لامدا تملكمعلمة الإدخال واحدة; وإلا فإنها تكون إلزامية. يتم فصل معلمتي إدخال أو أكثر من معلمات إدخال بفواصل بين زوجي أقواس:
(x, y) => x == y
في بعض الأحيان يكون صعبًا أو مستحيلاً على المحول البرمجي الاستدلال على أنواع المدخلات. عند حدوث ذلك، يمكنك تحديد الأنواع بوضوح كما هو موضح في المثال التالي:
(int x, string s) => s.Length > x
تعيين صفر من معلمات الإدخال مع أقواس فارغة:
() => SomeMethod()
لاحظ في المثال السابق نص تعبير لامدا يمكن أن يتألف من أسلوب الاستدعاء. ومع ذلك، إذا كنت تقوم بإنشاء تعبير الأشجار التي سوف يتم استهلاكه ضمن مجال آخر، مثل خادم SQL, يجب عدم استخدامه أسلوب الاستدعاءات في تعبيرات لامدا. ستكون الأساليب بلا معنى خارج سياق وقت تشغيل اللغة العامة في .NET .
كشف لامدا
وتمثل لامدا كشف لامدا تعبير إلا أن البيانات قد تم تضمينها في أقواس:
(input parameters) => {statement;}
يمكن أن تتكون هيئة لامدا الكشف من أي عدد من الكشوفات؛ ومع ذلك، من الناحية العملية لا يوجد هناك عادة أكثر من اثنين أو ثلاثة.
delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");
لا يمكن استخدام كشف لامدا لإنشاء تعبير الشجرة, مثل الأساليب المجهولة.
لامدا مع عوامل تشغيل الاستعلام القياسي
تحتوي العديد من عوامل تشغيل الاستعلام القياسي على معلمة إدخال يكون نوعها واحدة من عائلة Func<T, TResult>للتفويضات العامة. التفويضاتFunc<T, TResult> تستخدم نوع المعلمات لتعريف الرقم و نوع معلمة الإدخال و نوع الإرجاع للتفويض. المفوضين Funcمفيد جداً لتغليف التعبيرات المعرفة من قبل المستخدم التي يتم تطبيقها على كل عنصر في مجموعة من بيانات المصدر. على سبيل المثال، يجب اعتبار نوع التفويض التالي:
public delegate TResult Func<TArg0, TResult>(TArg0 arg0)
يمكن إنشاء مثيل المفوض Func<int,bool> myFunc حيث يكون int كمعلمة إدخال و bool هي قيمة الإرجاع. يتم تعيين قيمة الإرجاع دوماً في نوع معلمة آخر. Func<int, string, bool> تعرّف تفويض مع معلمتين من معلمات الإدخال, int و string، و نوع إرجاع bool. عند استدعاء التفويض التالي Func سيتم إرجاع صواب أو خطأ للإشارة إلى ما إذا كان يساوي معلمة الإدخال 5:
Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course
يمكن أيضاً تطبيق تعبير لامدا عندما يكون نوع الوسيطة Expression<Func>، على سبيل المثال في مشغل الاستعلام القياسية التي تم تعريفها في النظام.Linq.Queryable. عند تحديد وسيطة Expression<Func>، فسوف يتم تحويل لامدا برمجياً إلى تعبير الشجرة.
مشغل الاستعلامات القياسي, أسلوب Count ظاهر هنا:
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
يمكن للمحول البرمجي الاستدلال على نوع معلمة الإدخال, أو يمكنك تحديد ذلك أيضًا بوضوح. تعبير لامدا هذا يحسب تلك الأعداد الصحيحة (n) الذي يكون ما تبقى 1 عند القسمة على اثنين.
وستنتج الأسلوب التالي تسلسل يحتوي على كافة العناصر الموجودة في مجموعة الأرقام الموجودة إلى اليسار "9" لأن هذا هو الرقم الأول في التسلسل الذي لا يحقق الشرط:
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);
يوضح هذا المثال كيفية تحديد معلمات إدخال متعددة بواسطة إحاطتها بين قوسين. الأسلوب يرجع كلالعناصر في أرقام الصفيف حتى يصبح رقم مصادفة قيمته أقل من موضعه. لا تخلط بين عامل لامدا (=>) مع عامل التشغيل أكبر من أو يساوي>=).
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
استنتاج النوع في لامدا
عند كتابة lambdas، ليس عليك غالباً تحديد نوع لمعلمات الإدخال لأن المحول البرمجي يمكنه استنتاج نوع قائم على هيئة لامدا ونوع المفوض الأساسي وعوامل أخرى كما هو موضح في مواصفات لغة C#. للحصول على معظم مشغلات الاستعلام القياسي، فأن المدخل الأول هو نوع العناصر في تسلسل المصدر. كذلك إذا كنت تقوم بالاستعلام IEnumerable<Customer>، ثم يتم الإشارة لمتغير الإدخال ليصبح كائن Customer مما يعني أن لك حق الوصول إلى لأساليبه وخصائصه:
customers.Where(c => c.City == "London");
قواعد lambdas العامة هي كالتالي:
لامدا يجب أن يحتوي على نفس عدد المعلمات مثل نوع التفويض.
يجب أن تكون كل معلمة إدخال في لامدا محولة ضمنياً إلى معلمة التفويض المقابلة لها.
يجب أن تكون قيمة إرجاع لامدا (إن وجد) محولة ضمنيًا إلى نوع إرجاع التفويض.
علما أن تعبيرات لامدا في حد ذاتها لا تملك نوع لأن نظام النوع الشائع لنوع أي مفهوم جوهري لـ " تعبير لامدا." ومع ذلك، إنها أحياناً ملائمة للتحدث بشكل غير رسمي من "نوع" تعبير لامدا. في هذه الحالات يشسر النوع لنوع التفويض أو نوع Expression الذي حوّل إليه تعبير لامدا.
نطاق متغير في تعبيرات لامدا
يمكن أن تشير lambdas إلى متغيرات خارجية الموجودة في نطاق في الأسلوب أو النوع الذي يعرف لامدا المضمنة. يتم تخزين المتغيرات الملتقطة بهذه الطريقة للاستخدامها في تعبير لامدا حتى ولو انتقلت المتغيرات لخارج النطاق فإنه يتم تجميع البيانات المهملة. يجب أن يتم تعيين متغير خارجي بالتأكيد قبل أن يتم استهلاكها في تعبير لامدا. يوضح المثال التالي هذه الإمكانيات:
delegate bool D();
delegate bool D2(int i);
class Test
{
D del;
D2 del2;
public void TestMethod(int input)
{
int j = 0;
// Initialize the delegates with lambda expressions.
// Note access to 2 outer variables.
// del will be invoked within this method.
del = () => { j = 10; return j > input; };
// del2 will be invoked after TestMethod goes out of scope.
del2 = (x) => {return x == j; };
// Demonstrate value of j:
// Output: j = 0
// The delegate has not been invoked yet.
Console.WriteLine("j = {0}", j);
// Invoke the delegate.
bool boolResult = del();
// Output: j = 10 b = True
Console.WriteLine("j = {0}. b = {1}", j, boolResult);
}
static void Main()
{
Test test = new Test();
test.TestMethod(5);
// Prove that del2 still has a copy of
// local variable j from TestMethod.
bool result = test.del2(10);
// Output: True
Console.WriteLine(result);
Console.ReadKey();
}
}
تطبق القواعد التالية إلى نطاق متغير في تعبيرات لامدا:
المتغير الذي تم التقاطه لن يجمع البيانات المهملة للمفوض الذي يشير إليه فإنه يذهب إلى خارج النطاق.
المتغيرات المقدمة ضمن تعبير لامدا الغير مرئي في الأسلوب الخارجي.
يتعذر على تعبير لامدا الإلتقاط المباشر لمعلمات ref أو out من أسلوب المضمَّنة.
لا يتسبب كشف الارجاع في تعبير لامدا بأسلوب المضمنة للارجاع.
لا يمكن أن يحتوي تعبير لامدا على كشف goto أو كشف break أو كشف continue الذي يكون الهدف الخاص منه خارج النص أو في نص دالة المجهول المضمنة.
مواصفات لغة #C
لمزيد من المعلومات، راجع مواصفات لغة #C. مواصفات اللغة هي المصدر النهائي لبناء جملة C# واستخدامها.
راجع أيضًا:
المرجع
الأساليب المجهولة (دليل البرمجة لـ #C)
المبادئ
أشجار التعبير (C# و Visual Basic)