Thuộc tính (attribute) trong C#, là một thẻ khai báo, được sử dụng để truyền thông tin tới runtime về các hành vi của các phần tử khác nhau như các lớp, phương thức, cấu trúc, enum, assembly… trong chương trình của bạn. Bạn có thể thêm thông tin khai báo vào chương trình bằng cách sử dụng attribute. Một thẻ khai báo được mô tả bởi các dấu ngoặc vuông ([]) đặt bên trên phần tử mà nó được sử dụng cho.
Các Attribute được sử dụng để thêm metadata, ví dụ như chỉ lệnh biên dịch và thông tin khác như comment, mô tả, phương thức và các lớp vào một chương trình. .Net Framework cung cấp hai kiểu attribute: thuộc tính được định nghĩa trước (pre-defined attribute) và thuộc tính tùy chỉnh (custom built attribute).
Nội dung chính
Định nghĩa một Attribute trong C#
Cú pháp để xác định một Attribute trong C# như sau:
[attribute(positional_parameter, name_parameter = giá_trị, ...)] element
Tên của Attribute và giá trị của nó được xác định bên trong dấu ngoặc vuông, ở trước phần tử từ đó thuộc tính được áp dụng cho. positional_parameter xác định thông tin thiết yếu và name_parameter xác định thông tin tùy ý.
Attribute được định nghĩa trước trong C#
.Net Framework cung cấp 3 Attribute được định nghĩa trước:
- AttributeUsage
- Conditional
- Obsolete
AttributeUsage trong C#
Attribute được định nghĩa trước AttributeUsage miêu tả cách một lớp custom Attribute có thể được sử dụng. Nó xác định kiểu của các item, mà từ đó Attribute có thể áp dụng cho.
Cú pháp để xác định Attribute này trong C# như sau:
[AttributeUsage( validon, AllowMultiple=allowmultiple, Inherited=inherited )]
Trong đó:
Tham số validon xác định các phần tử ngôn ngữ mà Attribute có thể được đặt. Nó là một sự tổ hợp giá trị của một AttributeTargets enumerator. Giá trị mặc định là AttributeTargets.All.
Tham số allowmultiple (tùy ý) cung cấp giá trị cho thuộc tính AllowMultiple của attribute này, một giá trị Boolean. Nếu điều này là true, Attribute là multiuse. Giá trị mặc định là false (tức là single-use).
Tham số inherited (tùy ý) cung cấp giá trị cho thuộc tính Inherited của attribute này, một giá trị Boolean. Nếu nó là true, Attribute được kế thừa bởi các lớp kế thừa. Giá trị mặc định là false (không được kế thừa).
Ví dụ:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Feild | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]
Conditional trong C#
Attribute tiền định nghĩa này đánh dấu một phương thức có điều kiện mà sự thực thi của nó phụ thuộc vào một tiến trình tiền xử lý định danh đã cho.
Nó tạo sự biên dịch có điều kiện của các lời gọi phương thức, phụ thuộc vào giá trị đã cho, như Debug hoặc Trace. Ví dụ: nó hiển thị các giá trị của các biến trong khi debug một code.
Cú pháp để xác định Attribute này trong C# là như sau:
[Conditional( conditionalSymbol )]
Ví dụ:
[Conditional("DEBUG")]
Sau đây là ví dụ minh họa Conditional trong C#: Tạo hai lớp có tên lần lượt là TestAttribute, TestScharp như sau:
Lớp TestAttribute:
#define DEBUG using System; using System.Diagnostics; namespace KienThucLapTrinhCsharp { class TestAttribute { [Conditional("DEBUG")] public static void Message(string msg) { Console.WriteLine(msg); } } }
Lớp TestCsharp:
using System; namespace KienThucLapTrinhCsharp { class TestCsharp { static void function1() { TestAttribute.Message("Trong Function 1."); function2(); } static void function2() { TestAttribute.Message("Trong Function 2."); } public static void Main() { Console.WriteLine("Attribute trong C#"); Console.WriteLine("-----------------------"); TestAttribute.Message("Trong ham Main."); function1(); Console.ReadKey(); } } }
Nếu bạn không sử dụng lệnh Console.ReadKey(); thì chương trình sẽ chạy và kết thúc luôn (nhanh quá đến nỗi bạn không kịp nhìn kết quả). Lệnh này cho phép chúng ta nhìn kết quả một cách rõ ràng hơn.
Biên dịch và chạy chương trình C# trên sẽ cho kết quả sau:
Obsolete trong C#
Attribute tiền định nghĩa này trong C# đánh dấu một thực thể chương trình mà không nên được sử dụng. Nó cho bạn khả năng để thông báo cho compiler để loại bỏ một phần tử target cụ thể. Ví dụ, khi một phương thức mới đang được sử dụng trong một lớp và nếu bạn vẫn muốn giữ lại phương thức cũ trong lớp này, bạn có thể đánh dấu nó là obsolete bằng việc hiển thị một thông báo là phương thức mới nên được sử dụng, thay cho phương thức cũ.
Cú pháp để xác định Attribute này trong C# là như sau:
[Obsolete( message )] [Obsolete( message, iserror )]
Trong đó,
Tham số message là một chuỗi miêu tả lý do tại sao item là obsolete và cái gì được sử dụng thay cho nó.
Tham số iserror là một giá trị Boolean. Nếu giá trị của nó là true, compiler nên đối xử sự sử dụng của item này như là một lỗi. Giá trị mặc định là false (tức là compiler tạo một warning).
Ví dụ sau minh họa obsolete trong C#:
using System; namespace KienThucLapTrinhCsharp { class TestCsharp { [Obsolete("Dung su dung PhuongThuc1, ban nen su dung PhuongThuc2", true)] static void PhuongThuc1() { Console.WriteLine("Day la phuong thuc 1."); } static void PhuongThuc2() { Console.WriteLine("Day la phuong thuc 2."); } public static void Main() { PhuongThuc1(); // co dau gach do bao hieu tai day } } }
Khi đó, ở lời gọi PhuongThuc1() trong hàm main() sẽ xuất hiện dấu gạch đỏ, nếu bạn rê chuột qua sẽ có một thông báo có dạng:
Tạo Custom Attribute trong C#
Còn gọi là Attribute tùy biến hay Attribute do người dùng tự định nghĩa. .Net Framework cho phép tạo các Custom Attribute mà có thể được sử dụng để lưu giữ thông tin tường thuật và có thể được thu nhận tại runtime. Thông tin này có thể liên quan tới bất kỳ phần tử target nào phụ thuộc vào chuẩn thiết kế và yêu cầu ứng dụng.
Tạo và sử dụng Custom Attribute trong C# bao gồm 4 bước sau:
- Khai báo một Custom Attribute
- Xây dựng Custom Attribute
- Áp dụng Attribute trên một phần tử chương trình target
- Truy cập các Attribute thông qua Reflection
Bước cuối cùng liên quan tới việc viết một chương trình đơn giản để đọc qua metadata để tìm ra các notation đa dạng. Metadata là dữ liệu hoặc thông tin được sử dụng để miêu tả dữ liệu khác. Chương trình này nên sử dụng các Reflection để truy cập các Attribute tại runtime. Chúng ta sẽ bàn luận điều này trong chương tới.
Khai báo một Custom Attribute trong C#
Một Custom Attribute mới nên được kế thừa từ lớp System.Attribute trong C#. Ví dụ:
//a custom attribute BugFix to be assigned to a class and its members [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)]public class DeBugInfo : System.Attribute
Trong code trên, chúng ta đã khai báo một Custom Attribute là DeBugInfo.
Xây dựng Custom Attribute trong C#
Chúng ta cùng xây dựng Custom Attribute có tên là DeBugInfo, mà lưu giữ thông tin thu được bởi việc debug bất kỳ chương trình nào. Nó có thể giữ thông tin sau:
- Số hiệu code để bug
- Tên lập trình viên, người nhận diện bug đó
- Ngày review cuối cùng của code đó
- Một thông báo dạng chuỗi để lưu giữ các lưu ý của lập trình viên
Lớp DeBugInfo có 3 thuộc tính private để lưu giữ 3 thông tin đầu tiên và một thuộc tính public để lưu giữ thông báo đó. Vì thế, số hiệu bug, tên lập trình viên, và ngày review là các tham số vị trí tương ứng của lớp DeBugInfo và thông báo là một tham số tùy ý.
Mỗi Attribute phải có ít nhất một constructor. Các tham số vị trí tương ứng nên được truyền thông qua constructor đó. Ví dụ sau minh họa lớp DeBugInfo trên:
//Vi du minh hoa mot custom attribute BugFix [AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true)] public class DeBugInfo : System.Attribute { private int bugNo; private string developer; private string lastReview; public string message; public DeBugInfo(int bg, string dev, string d) { this.bugNo = bg; this.developer = dev; this.lastReview = d; } public int BugNo { get { return bugNo; } } public string Developer { get { return developer; } } public string LastReview { get { return lastReview; } } public string Message { get { return message; } set { message = value; } } }
Áp dụng Custom Attribute trong C#
Custom Attribute trong C# được áp dụng bằng việc đặt nó ngay trước target của nó:
[DeBugInfo(45, "Thanh Cong", "6/8/2015", Message = "Kieu tra ve khong hop le")] [DeBugInfo(49, "Hanh Phuc", "10/10/2015", Message = "Bien chua duoc su dung")] class Rectangle { //cac bien thanh vien protected double chieu_dai; protected double chieu_rong; public Rectangle(double l, double w) { chieu_dai = l; chieu_rong = w; } [DeBugInfo(55, "Thanh Cong", "6/8/2015", Message = "Kieu tra ve khong hop le")] public double tinhDienTich() { return chieu_dai * chieu_rong; } [DeBugInfo(56, "Hanh Phuc", "10/10/2015")] public void Display() { Console.WriteLine("Chieu dai: {0}", chieu_dai); Console.WriteLine("Chieu rong: {0}", chieu_rong); Console.WriteLine("Dien tich: {0}", tinhDienTich()); } }
Trong chương tới, chúng ta thu hồi thông tin Attribute bởi sử dụng một đối tượng lớp Reflection trong C#.