Kiểu ẩn danh (Anonymous Type) cung cấp một cách thuận tiện để đóng gói (encapsulate) một tập các thuộc tính chỉ đọc (read-only properties) vào một đối tượng mà không cần phải xác định rõ ràng loại (type) của nó ngay lúc viết code. Do đó, type name sẽ được tạo ra bởi trình biên dịch và không có sẵn trong mã nguồn. Và type của mỗi thuộc tính cũng được suy ra bởi trình biên dịch. Tức là tính năng này cho phép chúng ta tạo type mới (user-defined) mà không cần xác định tên của nó.
– Bạn tạo các type ẩn danh này bằng cách sử dụng toán tử new cùng với tính năng object initializer. Ví dụ sau đây cho thấy một kiểu ẩn danh là person được khởi tạo với 2 thuộc tính name và age:
var person = new { name = "www.minhhn.com", age = 20 };
- Khai báo một kiểu ẩn danh person, với kiểu/loại dữ liệu không quan tâm đến, mà chỉ quan tâm cái kiểu đó có 2 thuộc tính là name và age. Và sau đó có thể sử dụng 2 thuộc tính này như bình thường:
Console.WriteLine("name: " + person.name + ", age: " + person.age);
name: www.minhhn.com, age: 20
– Bắt buộc phải sử dụng tính năng khai báo kiểu ẩn danh (Anonymous Type) chung với var (xem bài tính năng Khai báo biến kiểu ngầm định (Implicitly Typed Local Variable)). Nếu chúng ta không làm vậy mà sử dụng type object thay thế cho var thì khi intellisense sẽ không thấy được 2 thuộc tính name và age, vì type object không có 2 thuộc tính này :
Nếu muốn gửi kiểu person này đến một method khác thì sẽ thế nào!?
– Lúc này chỉ có cách gửi kiểu person thông qua kiểu là object ở method nhận chứ không còn cách nào khác, vì chỉ có kiểu object mới nhận được mọi kiểu dữ liệu.
namespace MinhHoangBlog { class Program { static void Main(string[] args) { var person = new { name = "www.minhhn.com", age = 20 }; Console.WriteLine("name: " + person.name + ", age: " + person.age); // Truyền anonymous type cho method khác DoSomething(person); } private static void DoSomething(object objPerson) { // To do something ... } } }
– Tuy nhiên cách làm thế này thì cũng như ở , trong method DoSomething() cũng không thấy được 2 thuộc tính name và age. Để lấy được giá trị của 2 thuộc này, bạn có thể sử dụng Reflection khá là phức tạp:
private static void DoSomething(object objPerson) { // To do something ... var name = objPerson.GetType().GetProperty("name") .GetValue(objPerson, null); // www.minhhn.com var age = objPerson.GetType().GetProperty("age") .GetValue(objPerson, null); // 20 }
– Hoặc có cách đơn giản hơn, bạn có thể truyền nó cho một phương thức chấp nhận một tham số của kiểu dynamic. Tuy nhiên, việc passing anonymous types bằng cách sử dụng dynamic không được khuyến nghị (not recommended):
private static void DoSomething(dynamic param) { Console.WriteLine("name: " + param.name + ", age: " + param.age); }
– Qua ví dụ trên chúng ta thấy rằng: tính năng Anonymous Type thường được sử dụng cho xử lý nội bộ hàm mà không pass dữ liệu của kiểu đó ra ngoài hàm mà anonymous type được khai báo. Vì bên trong hàm khai báo anonymous type, chúng ta có thể dễ dàng access các thuộc tính của nó.
Anonymous Type với truy vấn LINQ
– Mệnh đề select của Linq sẽ tạo một Anonymous Type là kết quả của một truy vấn bao gồm các thuộc tính khác nhau mà không được xác định trong bất kỳ lớp nào. Chúng ta cùng xem ví dụ sau:
using System.Linq; using System.Collections.Generic; namespace MinhHoangBlog { public class Student { public int id { get; set; } public string name { get; set; } public string gender { get; set; } public int age { get; set; } public int mobile { get; set; } public string address { get; set; } } class Program { static void Main(string[] args) { List<Student> listStudent = new List<Student>() { new Student() { id = 1, name = "Minh", gender = "Male", age = 18, mobile = 123, address = "Japan" } , new Student() { id = 2, name = "Hoang", gender = "Male", age = 21, mobile = 456, address = "Korea" } , new Student() { id = 3, name = "Blog", gender = "Female", age = 18, mobile = 789, address = "Vietnam" } , new Student() { id = 4, name = "minhhn.com", gender = "Male", age = 20, mobile = 6868, address = "Slovakia" } , new Student() { id = 5, name = "Hi!", gender = "Female", age = 21, mobile = 9999, address = "Usa" } }; var studentResult1 = from s in listStudent select new { StudentID = s.id, StudentName = s.name }; // Hoặc ngắn gọn hơn var studentResult2 = listStudent.Select(s => new { StudentID = s.id, StudentName = s.name }); var studentResult3 = listStudent.Select(s => new { s.id, s.name }); } } }
– Trong ví dụ trên, lớp Student bao gồm nhiều thuộc tính khác nhau. Trong method Main(), mệnh đề Linq select tạo một anonymous type chỉ bao gồm id và name thay vì bao gồm tất cả các thuộc tính trong kết quả trả về. Vì vậy, nó rất hữu ích trong việc tiết kiệm bộ nhớ và code không cần thiết. Collection kết quả trả về của truy vấn chỉ bao gồm các thuộc tính StudentID và StudentName như được hiển thị trong chế độ xem debug sau đây:
Tổng kết
– Anonymous type có thể được xác định bằng cách sử dụng từ khóa new và cú pháp khởi tạo đối tượng object initializer.
– Khai báo biến kiểu ngầm định (Implicitly Typed Local Variable) – var được sử dụng để giữ một anonymous type.
– Anonymous type là loại tham chiếu (reference type) và tất cả các thuộc tính là chỉ đọc (read-only).
– Phạm vi của một anonymous type là cục bộ (local), là trong phạm vi của phương thức định nghĩa ra nó.
– Anonymous types là các class types xuất phát trực tiếp từ object và không thể truyền sang bất kỳ loại nào ngoại trừ object.
[…] Lập trình C# […]