Lambda-Expressions trong C#
Ngôn ngữ mình tiếp cận theo kiểu thực sự quan tâm đầu tiên là Javascript, một ngày nọ mình làm quen với C# và thấy nó cũng có cái dấu “=>” như trong Arrow function trong thằng JS thế là mình bắt đầu đi vào tìm hiểu thằng này xem cách sử dụng nó ra sao
Có thể nói so với anonymous method, lambda expression được coi là một sự cái tiến đáng giá từ phiên bản C# 2.0 lên C# 3.0. Khi dùng anonymous method, bạn có thể tạo các hàm in-line nhằm hạn chế việc khai báo các hàm riêng lẻ không cần thiết, giúp mã lệnh ngắn gọn hơn. Nay với lambda expression, bạn có thể viết ngắn gọn và dễ dàng hơn nhờ việc cung cấp toán tử và cú pháp mới, đồng thời thể hiện sự “thông minh” của compiler bằng cách tự nhận diện kiểu của dữ liệu.
1.Lambda Expressions là gì
Lamda Expression là một hàm không có tên (unamed function) với các tham số (parameters) và nội dung thực thi (body). Nội dung thực thi của Lamda expression có thể là 1 khối lệnh hoặc 1 biểu thức. Dấu “=>” tách biệt các tham số và nội dung thực thi, mình thấy nó khá tương đồng vs Arrow function trong JS
2 .Áp dụng cú pháp Lambda Expressions
1. Có thể bỏ qua kiểu dữ liệu của parameter truyền vào
1 2 3 4 | (string name) => {Console.WriteLine("Hello: " + name);} (name) => {Console.WriteLine("Hello: " + name);} |
=> 2 cách viết trên là tương đương nhau, compiler đã tự nhận diện kiểu của dữ liệu và thực thi
2. Nếu không có parameter, bỏ dấu () trống
1 2 | () => {Console.WriteLine("Hello");} |
=> Đây là phần bắt buộc để phân biệt phần tham số, nếu bạn bỏ cả dấu “()” khi mà không có parameter thì chương trình sẽ lỗi
3. Nếu chỉ có 1 parameter, có thể bỏ luôn dấu ()
1 2 3 4 5 | (x) => {Console.WriteLine("Hello " + x);} x => {Console.WriteLine("Hello " + x);} |
=> 2 Cú pháp trên là tương đương nhau, nhớ rằng chỉ có 1 tham số ta mới dùng được như thế, nếu có 2 tham số mà bạn không để bên trong dấu “()” thì chương trình sẽ báo lỗi
1 2 | x, y => {Console.WriteLine("Hello " + x + y);} //Sai |
4. Nếu có nhiều parameter, ngăn cách bằng dấu phẩy
1 2 | (x, y) => {Console.WriteLine("Hello " + x + y);} |
5. Nếu anonymous function chỉ có 1 câu lệnh, có thể bỏ dấu “{}”
1 2 3 4 | x => { Console.WriteLine("Hello " + x); } x => Console.WriteLine("Hello " + x) |
=> 2 cú pháp trên là tương đương nhau, chỉ áp dụng cho phần thực thi có 1 câu lệnh, nếu có trên 1 câu lệnh bắt buộc bạn phải bỏ chúng trong dấu “{}”
6. Nếu chỉ return 1 giá trị, có thể bỏ chữ return
1 2 3 4 5 6 7 8 9 10 | //4 lambda expression sau tương đương nhau (x) => { return x > 4; } x => { return x > 4; } x => return x > 4 x => x > 4 |
Khái quát cách rút gọn 1 lambda expressions:
Để tìm hiểu rõ hơn, mình sẽ đi vào 1 ví dụ cụ thể với ASP .NET bên dưới
3. Ví dụ lambda expressions với ASP .NET
3.1. Tạo 1 Project ASP .NET MVC
3.2. Tạo Model
- Tạo 1 Model tên Book trong folder Models và cấu hình như sau
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace LambdaExpressionsDemo.Models { public class Book { public int Id { get; set; } public String Name { get; set; } public String Author { get; set; } public decimal Price { get; set; } public DateTime Published { get; set; } } } |
3.3. Tạo Context và kết nối đến cơ sở dữ liệu
- Mở SQL sever và tạo 1 database LibraryDB:
- Cài đặt nuget package Entity Framework vào project:
- Tạo thư mục Context trong project và tạo file BookContext.cs để cấu hình context kết nối dữ liệu
- Cấu hình BookContext.cs như sau
1 2 3 4 5 6 7 8 9 10 11 12 13 | using LambdaExpressionsDemo.Models; using System; using System.Collections.Generic; using System.Data.Entity; using System.Linq; using System.Web; namespace LambdaExpressionsDemo.Context { public class BookContext : DbContext{ public DbSet<Book> Books { get; set; } } } |
- Kết nối đến sever/Database vừa tạo:
- Tiếp theo cấu hình Webconfig.cs, nếu chưa biết cấu hình bạn có thể tham khảo bài viết Code first trong ASP .NET của mình phần connect database , thêm đoạn XML tương tự này vào thẻ configuration
1 2 3 4 | <connectionStrings> <add name="BookContext" connectionString="Data Source=DESKTOP-E2I8M9USQLEXPRESS;Initial Catalog=LibraryDB;Integrated Security=True" providerName="System.Data.SqlClient"/> </connectionStrings> |
3.4. Tạo Controller và View
- Tạo controller BookController.cs trong thư mục Controllers cấu hình như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | using LambdaExpressionsDemo.Context; using LambdaExpressionsDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace LambdaExpressionsDemo.Controllers { public class BookController : Controller { BookContext db = new BookContext(); //Tạo context để kết nối đến database // GET: Book public ActionResult Index() { return View(db.Books.ToList()); } // GET: Book/Details/5 public ActionResult Details(int id) { return View(); } // GET: Book/Create public ActionResult Create() { return View(); } // POST: Book/Create [HttpPost] public ActionResult Create(FormCollection collection) { try { // TODO: Add insert logic here return RedirectToAction("Index"); } catch { return View(); } } // GET: Book/Edit/5 public ActionResult Edit(int id) { return View(); } // POST: Book/Edit/5 [HttpPost] public ActionResult Edit(int id, FormCollection collection) { try { // TODO: Add update logic here return RedirectToAction("Index"); } catch { return View(); } } // GET: Book/Delete/5 public ActionResult Delete(int id) { return View(); } // POST: Book/Delete/5 [HttpPost] public ActionResult Delete(int id, FormCollection collection) { try { // TODO: Add delete logic here return RedirectToAction("Index"); } catch { return View(); } } } } |
- Tiến hành Rebuild Project, và click chuột phải vào vùng Action Index chọn add View:
- Cấu hình View như sau:
- Thêm các ActionLink sau vào /View/Book/Index.cshtml vừa tạo:
- Tạo view cho method GET Book/Create ở BookControlle.cs:
- Cấu hình Action Create cho method POST Book/Create ở BookControlle.cs:
- Giờ thì Run App và thêm 1 vài dữ liệu vào để sử dụng nào
3.5. Sử dụng Lambda Expressions và LINQ để lọc dữ liệu
- Nếu chưa có kiến thức về LINQ thì bạn có thể tham khảo bài viết về LinQ trong .NET framework của mình.
- Quay lại BookController và thêm ActionResult ShowAfter1990 như sau:
- Tiến hành Add View cho Action này:
- Run App => Và kết quả là ta đã sử dung được chức năng lọc các sách được phát hành sau năm 1990:
- Còn chức năng của Action ShowAfter2000 các bạn tự làm thử tương tự nhé
3.6. Giải thích ví dụ
Ở trên mình đã sử dụng cú pháp Lambda :
1 2 | db.Books.Where(b => b.Published >= new DateTime(1990, 1, 1)); |
Tường minh của câu truy vấn này là:
1 2 | var books = from book in db.Books where (book.Published >= new DateTime(1990, 1, 1)) select book; |
Rất dài dòng so với dùng lambda expression phải không
4. Tổng kết
- Theo mình thì lambda expression một sự cải tiến hay nâng cấp tốt. Nó giúp chúng ta viết ngắn code nhưng vẫn dễ hiểu, và dễ học.
- Hơn nữa vì đa số các lập trình viên đều thích nhìn các ký hiệu, toán tử vì nó tượng hình thay vì dùng các chữ, kỹ tự khô khan nên chắc hẳn đây sẽ làm 1 cú pháp khá thú vị