Series C# hay ho: Những điều thú vị trong C# (Phần 2)

Chào mừng các bạn đã quay lại với phần 2 bài viết Những điều thú vị trong C#. Bạn có thể xem lại phần 1 ở đây:

https://toidicodedao.wordpress.com/2015/01/22/series-c-hay-ho-nhung-dieu-thu-vi-trong-c-phan-1/

Series C# hay ho là một series dài kì, giới thiệu những điều “hay ho” của C#. Đây chỉ là phần 2 của bài viết thôi, không phải của toàn bộ series đâu nhé.

1. Optional Parameters

Có 1 số bạn sẽ không biết optional parameters là gì (Mình thì biết nó từ C++, tuy nhiên gần đây mới biết là C# cũng có =)). Giả sử không có optional parameter, ta muốn chạy những function Add như sau


 Add(1, 2);
 Add(1, 2, 3.5);
 Add(1, 2, 3.5, "Hello");
 Add(1, 2, true);

Ta cần phải viết overload lại function Add những 4 lần.


 public int Add(int num1, int num2)
 public int Add(int num1, int num2, double num3)
 public int Add(int num1, int num2, double num3, string num4)
 public int Add(int num1, int num2, bool bol)

Vô cùng phiền phức và mất thời gian phải ko? Với optional parameters, ta có thể viết 1 function nhận vào toàn bộ tham số, và chỉ định 1 số tham số là option, nếu ko đưa vào sẽ sử dụng giá trị mặc định:


 public int Add(int num1, int num2,
                double num3 = 0, string num4 = "", bool bol = true)

//Câu lệnh Add(1, 2, true);, vì skip num3 và num4, ta sẽ gọi
Add(1, 2, bol: false);

//2 câu lệnh sau sẽ tương đương nhau.
//Khi ta không truyền vào num3, num4, chúng sẽ dùng giá trị default
Add(1, 2);
Add(1, 2, 0, "", true);

Nếu các bạn đã học C++ chắc cũng không lại gì với khái niệm này. Như đã thấy, nó giúp chúng ta tiết kiệm được khá nhiều thời gian code. (Nói nhỏ các bạn nghe, trong Java và javascript không có optional parameters đâu, vì vậy thường thường chúng ta phải overload 1 hàm nhiều lần, rất chi là cực -_-).

2. Anonymous Type

Như đã nhắc đến ở phần 1, Anonymous Type rất hữu dụng trong nhiều trường hợp. Giả sử chúng ta có 1 class Student với 10 properties.

public class Student
 {
  public string Name { get; set; }
  public int Age { get; set; }
  public string Name2 { get; set; }
  public int Age2 { get; set; }
  public string Field1 { get; set; }
  public string Field2 { get; set; }
  public string Field3 { get; set; }
  public string Field4 { get; set; }
  public string Field5 { get; set; }
  public string Field6 { get; set; }
 }

Trường hợp ta chỉ muốn lấy 2 fields Name và Age của Student để serialize ra JSON cho ngắn gọn, ta viết code như sau.

 List<Student> students = new List<Student>();
 var stu = students.Select(st => new {Name = st.Name, Age = st.Age});
 //Hoặc ngắn gọn hơn
 stu = students.Select(st => new {st.Name, st.Age });

Anonymous object nhận được sẽ là object với 2 properties: Name và Age. Object này còn được implement sẵn function Equals(), do đó ta có thể so sánh giữa 2 object dễ này. Tuy nhiên, ta cũng cần cẩn thận với một số trường hợp “tưởng bằng mà lại ko bằng”.

 var a = new {Name = "Hoang", Age = 10};
 var b = new { Name = "Hoang", Age = 10 };
 Console.WriteLine(a == b); // True

 //Cẩn thận những trường hợp sau
 var c = new { Name = "Hoang", Age = 10 };
 var d = new { Name = "Hoang", Age = 10.2 };
 var e = new { Age=10, Name = "Hoang", };
 Console.WriteLine(c == d); // Không compile, báo lỗi
 Console.WriteLine(c == e); // Không compile, báo lỗi

3. Tuple

Tuple là một khái niệm khá “lạ”, mình gặp khái niệm này lần đầu ở Python, giờ mới biết trong C# cũng có. Có thể hiểu đơn giản tuple là 1 “cục” tập hợp của nhiều fields, tương tự như class, nhưng define nhanh và dễ hơn. Ví dụ:

 var love = new Tuple<int>(1);
 var lie = new Tuple<int, string>(1, "Why");
 var lay = new Tuple<int, int, string>(1, 2, "Gay");
 Console.WriteLine(lay.Item1 + " " + lay.Item2 + " " + lay.Item3);// 1 2 Gay

Anonymous type có 1 khuyết điểm, đó là ko thể dùng anonymous type làm kiểu trả về, hoặc parameter truyền vào cho 1 function.

public ??? GetStu() //Làm sao trả về
 {
   List<Student> students = new List<Student>();
   var stu = students.Select(st => new {st.Name, st.Age });
   return stu;
 }

DoSomething(stu);
public void DoSomething(???); // Làm sao truyền vào

Với tuple, vấn đề đó được giải quyết nhanh chóng:

public List<Tuple<string, int>> GetStu()
 {
   List<Student> students = new List<Student>();
   var stu = students.Select(st => new Tuple<string, int>(st.Name, st.Age)).ToList();
   return stu;
 }

public void DoSomething( List<Tuple<string, int>> input);
DoSomething(stu);

Có thể các bạn sẽ hỏi: Tại sao ko tạo 1 class mới, dùng anonymous type với tuple làm gì cho mệt? Xin trả lời:

  • Có 1 số trường hợp ta cần extract 1 số field, nếu mỗi lần lấy vài fields ta đều tạo class mới thì code sẽ khá dư và vô nghĩa.
  • Nếu tạo class mới, ta phải override lại hàm Equals và GetHashCode nếu cần so sánh. Anonymous type và tuples đã tự động implement hàm này cho chúng ta.

4. String và những điều ít người biết

Chắc ai trong số chúng ta cũng đã từng dùng string để vẽ header, footer như thế này nhỉ?

==============================================================

Đoạn code chúng ta đã dùng là

 string header = "";
for (int i = 0; i < 80; i++)
 {
     header += "";
 }

//Cách đơn giản hơn với string, hẳn bạn sẽ rất bất ngờ =))
string header = new string('=', 80);

Tương tự, khi ta có 1 list các string, và ta muốn cộng toàn bộ các string trong list

 List<string> list = new List<string>{ "1" , "2" , "3"};
 string result = "";
 foreach (var str in list)
 {
     result += str + ",";
 }

//Đơn giản tới bất ngờ lần 2
 string result = string.Join(", ", list);

//Bá đạo hơn nữa khi ta join với param không phải string
string result = string.Join(", ", "Hello", 1, 2, 3.5); //Hello, 1, 2, 3.5

6. Khởi tạo Collection (ToArray, ToList, ToDictionary, …)

Khi sử dụng Linq, sau khi dùng Where, Select, … kết quả trả về thường là 1 IENumerable, ta có thể biến chúng thành List hoặc Array với các hàm có sẵn. ToList là hàm được sử dụng nhiều nhất:

 List<Student> students = new List<Student>();
 IEnumerable<Student> stu = students.Where(st => st.Age > 0);

//Tạo list
 List<Student> stuList = stu.ToList();

//Tạo array
 Student[] stuArray = stu.ToArray();

 //Tạo 1 dictionary, Key là Name, Value là Age
 Dictionary<string, int> stuDic = stu.ToDictionary(t => t.Name, t => t.Age);

Bài viết tới đây là kết thúc. Vì nội dung bài viết có hạn, một số phần mình chỉ giới thiệu tổng quan, ko đi sâu vào chi tiết. Những phần như Linq, Anonymous Type, Delegate, … sẽ có bài viết cụ thể đầy đủ hơn cho từng phần, mong các bạn đón xem.

Bài viết được phỏng dịch + lượt từ bản gốc tiếng Anh (Đã xin phép tác giả) : http://geekswithblogs.net/BlackRabbitCoder/archive/2011/10/24/c.net-little-wonders-the-complete-collection-again.aspx

11 thoughts on “Series C# hay ho: Những điều thú vị trong C# (Phần 2)”

  1. Hình như chỗ này chưa đúng thì phải
    string header = “”;
    for (int i = 0; i < 80; i++)
    {
    header += ""; // "="
    }

    Like

Leave a comment