Biểu thức Lambda

C# 3.0 (.NET Framework 3.5) đã giới thiệu biểu thức lambda cùng với LINQ. Biểu thức lambda là một cách ngắn hơn để biểu diễn phương thức ẩn danh bằng cách sử dụng một số cú pháp đặc biệt.

Ví dụ: phương thức ẩn danh sau kiểm tra nếu sinh viên là thiếu niên hay không (độ tuổi từ 13 đến 19):

delegate(Student s) { return s.Age > 12 && s.Age < 20; };

Phương thức ẩn danh ở trên có thể được biểu diễn bằng biểu thức Lambda trong C# như sau:

s => s.Age > 12 && s.Age < 20

Chúng ta hãy xem cách biểu thức lambda tiến hóa từ phương thức ẩn danh sau:

delegate(Student s) { return s.Age > 12 && s.Age < 20; };

Biểu thức Lambda tiến hóa từ phương thức ẩn danh bằng cách loại bỏ từ khóa delegate và kiểu dữ liệu của tham số rồi thêm toán tử lambda =>.

Biểu thức Lambda

Biểu thức lambda ở trên là hoàn toàn hợp lệ, nhưng chúng ta không cần dấu ngoặc nhọn, return và dấu chấm phẩy nếu chúng ta chỉ có một câu lệnh trả về giá trị. Vì vậy, chúng ta có thể loại bỏ nó.

Ngoài ra, chúng ta có thể loại bỏ dấu ngoặc đơn (), nếu chúng ta chỉ có một tham số.

Biểu thức Lambda

Do đó, chúng ta có biểu thức lambda: s => s.Age > 12 && s.Age < 20 trong đó s là một tham số, => là toán tử lambda và s.Age > 12 && s.Age < 20 là thân của biểu thức:

Biểu thức Lambda

Biểu thức Lambda với nhiều tham số

Bạn có thể đóng gói các tham số trong ngoặc đơn nếu bạn cần truyền nhiều hơn một tham số như sau:

(s, youngAge) => s.Age > youngage;

Bạn cũng có thể đưa ra kiểu dữ liệu của từng tham số nếu tham số gây nhầm lẫn như sau:

(Student s,int youngAge) => s.Age > youngage;

Biểu thức Lambda không có tham số

Không nhất thiết phải có ít nhất một tham số trong biểu thức lambda. Biểu thức lambda có thể được chỉ định mà không có bất kỳ tham số nào như ví dụ dưới đây:

() => Console.WriteLine("Parameter less lambda expression")

Nhiều câu lệnh trong thân của biểu thức Lambda

Bạn có thể đóng gói biểu thức trong dấu ngoặc nhọn nếu bạn muốn có nhiều hơn một câu lệnh trong thân của biểu thức Lambda như ví dụ dưới đây:

(s, youngAge) =>
{
    Console.WriteLine("Lambda expression with multiple statements in the body");
    
    return s.Age > youngAge;
}

Khai báo biến cục bộ trong thân của biểu thức Lambda

Bạn có thể khai báo biến trong thân của biểu thức Lambda để sử dụng nó ở bất cứ đâu trong thân của biểu thức như sau:

s =>
{
   int youngAge = 18;

    Console.WriteLine("Lambda expression with multiple statements in the body");

    return s.Age > youngAge;
}

Biểu thức Lambda cũng có thể được chỉ định cho các delegate tích hợp như Func , ActionPredicate .

Chỉ định biểu thức Lambda cho delegate

Delegate Func

Biểu thức lambda có thể được chỉ định để delegate kiểu Func<in T, out TResult>. Kiểu tham số cuối cùng trong một delegate Func là kiểu trả về và phần còn lại là các tham số đầu vào. Truy cập bài viết về  delegate Func trong lập trình C# để biết thêm về nó.

Ví dụ: biểu thức lambda sau đây được dùng để kiểm tra xem một học sinh có phải là một thiếu niên hay không (tuổi từ 13 - 19):

Func<Student, bool> isStudentTeenAger = s => s.Age > 12 && s.Age < 20;

Student std = new Student() { Age = 21 };

bool isTeen = isStudentTeenAger(std);// returns false

Trong ví dụ trên, delegate Func yêu cầu ​​tham số đầu vào đầu tiên là kiểu Student và kiểu trả về là boolean. Biểu thức lambda s => s.age > 12 && s.age < 20 thỏa mãn yêu cầu của delegate Func<Student, bool>, như được trình bày ở hình bên dưới:

Chỉ định biểu thức Lambda cho delegate

Delegate Func được trình bày ở trên hóa ra là một chức năng như được trình bày ở ví dụ bên dưới.

bool isStudentTeenAger(Student s)
{
    return s.Age > 12 && s.Age < 20;
}

Delegate Action

Không giống như delegate Func, delegate Action chỉ có các tham số đầu vào. Sử dụng kiểu delegate Action khi bạn không cần trả về bất kỳ giá trị nào từ biểu thức lambda.

Action<Student> PrintStudentDetail = s => 
    Console.WriteLine($"Name: {s.StudentName}, Age: {s.Age}");

Student std = new Student() 
{ 
    StudentName = "Bill",
    Age = 21 
};

PrintStudentDetail(std);//output: Name: Bill, Age: 21

Delegate Predicate

Không giống như delegate Action, delegate Predicate có các tham số đầu vào và luôn trả về kiểu boolean (có thể xem delegate Predicate là một delegate Func<in T, out bool>). Sử dụng kiểu delegate Predicate khi bạn cần trả về giá trị kiểu bool từ biểu thức lambda.

Predicate<Student> isStudentTeenAger = s => s.Age > 12 && s.Age < 20;

Student std = new Student() { Age = 18 };

bool isTeen = isStudentTeenAger(std);// returns true

Biểu thức Lambda trong truy vấn LINQ

Thông thường biểu thức lambda được sử dụng với truy vấn LINQ. Lớp tĩnh Enumerable bao gồm phương thức mở rộng Where cho các lớp triển khai interface IEnumerable<T> chấp nhận tham số delegate Func<TSource,bool>.

Vì vậy, phương thức mở rộng Where cho danh sách IEnumerable<Student> được yêu cầu phải truyền tham số Func<Student,bool>, như được hiển thị ở hình bên dưới:

Biểu thức Lambda trong truy vấn LINQ

Vì vậy, bây giờ bạn có thể truyền biểu thức lambda cho phương thức mở rộng Where trong cú pháp phương thức truy vấn LINQ như dưới đây:

IList<Student> studentList = new List<Student>(){...};

var teenStudents = studentList
    .Where(s => s.age > 12 && s.age < 20)
    .ToList<Student>();

Những điểm cần nhớ về biểu thức lambda

  1. Biểu thức Lambda là một cách ngắn hơn để biểu diễn phương thức ẩn danh.
  2. Cú pháp biểu thức Lambda: parameters => body expression
  3. Biểu thức Lambda có thể không có tham số.
  4. Biểu thức Lambda có thể có nhiều tham số đặt trong cặp dấu ngoặc đơn ().
  5. Biểu thức Lambda có thể có nhiều câu lệnh trong thân của biểu thức đặt trong cặp dấu ngoặc nhọn {}.
  6. Biểu thức Lambda có thể được gán cho delegate Func, Action hoặc Prateate.
  7. Biểu thức Lambda có thể được gọi theo cách tương tự như delegate.
LINQ
Bài Viết Liên Quan:
Truy vấn LINQ phức tạp
Trung Nguyen 23/04/2020
Truy vấn LINQ phức tạp

Bạn sẽ tìm hiểu một số truy vấn LINQ phức tạp trong hướng dẫn này.

Từ khóa let, into trong LINQ
Trung Nguyen 23/04/2020
Từ khóa let, into trong LINQ

Từ khóa let, into trong LINQ có tác dụng gì? Hướng dẫn khai báo và sử dụng từ khóa let, into trong LINQ.

Thực thi truy vấn LINQ
Trung Nguyen 23/04/2020
Thực thi truy vấn LINQ

Trì hoãn thực thi truy vấn LINQ là gì? Thực thi ngay lập tức truy vấn LINQ là gì? Làm sao để thực thi truy vấn LINQ.

Expression trong LINQ
Trung Nguyen 23/04/2020
Expression trong LINQ

Expression trong LINQ là gì? Cây biểu thức trong LINQ là gì? Cách khai báo và sử dụng chúng trong LINQ.