مقدمه

در درس قبل با متدهای ناشناس به عنوان راهی برای تعریف درون‌خطی یک نماینده آشنا شدیم. متدهای ناشناس کد را ساده‌تر کردند، اما سینتکس آن‌ها (delegate (...) { ... }) هنوز کمی طولانی بود. با معرفی C# 3.0 و تکنولوژی LINQ، نیاز به یک سینتکس بسیار مختصرتر و قدرتمندتر برای تعریف توابع ناشناس احساس می‌شد. پاسخ به این نیاز، عبارات لامبدا (Lambda Expressions) بود. عبارات لامبدا در برنامه‌نویسی مدرن C# جایگاه ویژه‌ای دارند و تقریباً به طور کامل جایگزین سینتکس متدهای ناشناس شده‌اند. آن‌ها سنگ بنای کار با LINQ و بسیاری از کتابخانه‌های مدرن هستند.

عبارت لامبدا چیست؟

یک عبارت لامبدا، در اصل یک سینتکس کوتاه‌تر برای نوشتن یک متد ناشناس است. این عبارت یک تابع ناشناس را تعریف می‌کند که می‌تواند به یک نماینده اختصاص داده شود یا به عنوان پارامتر به متدهایی که نماینده می‌پذیرند، ارسال گردد.

ساختار اصلی یک عبارت لامبدا به شکل زیر است:

(input-parameters) => expression-or-statement-block

عملگر => به عنوان عملگر لامبدا شناخته می‌شود و خوانده می‌شود "goes to" (می‌رود به). این عملگر، لیست پارامترهای ورودی را از بدنه‌ی عبارت جدا می‌کند.

از متد ناشناس تا لامبدا

برای درک سادگی لامبدا، بیایید یک نماینده‌ی Func<int, int, int> را ابتدا با یک متد ناشناس و سپس با یک عبارت لامبدا پیاده‌سازی کنیم.

Copy Icon Program.cs
// 1. Anonymous Method (C# 2.0)
Func<int, int, int> addAnonymous = delegate (int x, int y)
{
    return x + y;
};

// 2. Lambda Expression (C# 3.0 and later)
Func<int, int, int> addLambda = (x, y) => x + y;

Console.WriteLine($"Anonymous: {addAnonymous(5, 10)}");
Console.WriteLine($"Lambda:    {addLambda(5, 10)}");

همانطور که می‌بینید، عبارت لامبدا به طرز چشمگیری کوتاه‌تر و خواناتر است. کامپایلر به طور خودکار نوع پارامترهای x و y را از روی امضای نماینده‌ی Func<int, int, int> تشخیص می‌دهد. همچنین، چون بدنه‌ی متد تنها یک عبارت (x + y) است، نیازی به آکولاد {} و کلمه‌ی کلیدی return نیست.

کاربردهای عملی

عبارات لامبدا در تمام بخش‌هایی که از نمایندگان استفاده می‌شود، کاربرد دارند و به خصوص در کار با LINQ و رویدادها، ابزار اصلی محسوب می‌شوند.

کنترل رویدادها

می‌توانیم کنترل‌کننده‌ی رویداد Button.Click را با استفاده از یک لامبدا به صورت بسیار فشرده بنویسیم.

Copy Icon Program.cs
public class Button { public event EventHandler Click; /* ... */ }

Button myButton = new();
// Subscribing to an event with a lambda expression.
myButton.Click += (sender, e) => Console.WriteLine("Button was clicked!");

کوئری‌های LINQ

قدرت واقعی لامبدا در ترکیب با متدهای بسطی LINQ آشکار می‌شود. تقریباً تمام متدهای LINQ، نمایندگانی از نوع Func یا Action را به عنوان پارامتر می‌پذیرند و عبارات لامبدا بهترین راه برای ارسال منطق به این متدها هستند.

Copy Icon Program.cs
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };

// Use a lambda expression with the Where extension method from LINQ.
// n => n > 5 is a lambda that returns true if n is greater than 5.
var largeNumbers = numbers.Where(n => n > 5);

// Chaining multiple LINQ methods with lambdas.
var processedNumbers = numbers
    .Where(n => n % 2 == 0) // Filter for even numbers
    .Select(n => n * n);    // Project to their squares

Console.WriteLine(string.Join(", ", processedNumbers)); // Output: 4, 16, 36, 64

در این مثال، به جای نوشتن حلقه‌های پیچیده، ما با استفاده از متدهای LINQ و عبارات لامبدا، به شکلی اعلانی (declarative) و خوانا، خواسته‌ی خود را بیان کرده‌ایم: "از لیست اعداد، آن‌هایی را انتخاب کن که زوج هستند و سپس مربع آن‌ها را برگردان."