Attribute trong C#

Attribute là gì?

Attribute (thuộc tính) là một thẻ khai báo được sử dụng để truyền tải thông tin lúc thực thi về hành vi của các thành phần khác nhau như các lớp, phương thức, cấu trúc, liệt kê, tập hợp,... trong chương trình của bạn.

Bạn có thể thêm thông tin khai báo vào một chương trình bằng cách sử dụng một attribute. Thẻ khai báo được mô tả bằng dấu ngoặc vuông ([]) được đặt phía trên phần tử được sử dụng.

Các attribute được sử dụng để thêm siêu dữ liệu, như hướng dẫn trình biên dịch và các thông tin khác như nhận xét, mô tả, phương thức và lớp cho một chương trình.

.NET Framework cung cấp hai loại attribute: attribute được định nghĩa trước và attribute được xây dựng tùy chỉnh .

Chỉ định một attribute

Cú pháp để chỉ định một attribute như sau:

[attribute(positional_parameters, name_parameter = value, ...)]
element

Tên của attribute và các giá trị của nó được chỉ định trong dấu ngoặc vuông, trước phần tử được áp dụng attribute. Tham số vị trí xác định thông tin cần thiết và tham số tên chỉ định thông tin tùy chọn.

Attribute được định nghĩa trước

.NET Framework cung cấp ba attribute được định nghĩa trước:

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

Attribute được định nghĩa trước AttributeUsage mô tả cách sử dụng một lớp attribute tùy chỉnh. Nó chỉ định các loại thành phần mà thuộc tính có thể được áp dụng.

Cú pháp để chỉ định attribute này như sau:

[AttributeUsage (
   validon,
   AllowMultiple = allowmultiple,
   Inherited = inherited
)]

Ở đây:

  • Tham số validon chỉ định các thành phần mà attribute có thể được đặt. Nó là sự kết hợp của các giá trị của AttributeTargets. Giá trị mặc định là AttributeTargets.All .
  • Tham số allowmultiple (tùy chọn) cung cấp giá trị Boolean cho thuộc tính AllowMultiple của attribute này. Nếu tham số này là true, attribute có thể được đặt nhiều lần trên cùng một thành phần. Mặc định là false (sử dụng một lần).
  • Tham số inherited (tùy chọn) cung cấp giá trị Boolean cho thuộc tính Inherited của attribute này. Nếu tham số này là true, attribute được kế thừa bởi các lớp dẫn xuất. Giá trị mặc định là false (không được kế thừa).

Ví dụ:

[AttributeUsage(
   AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property, 
   AllowMultiple = true)]

Conditional

Attribute được định nghĩa trước này đánh dấu một phương thức có điều kiện mà việc thực thi phụ thuộc vào một định danh tiền xử lý được chỉ định.

Nó gây ra việc biên dịch có điều kiện các lệnh gọi phương thức, tùy thuộc vào giá trị được chỉ định như Debug hoặc Trace. Ví dụ, nó hiển thị các giá trị của các biến trong khi gỡ lỗi mã.

Cú pháp để chỉ định attribute này như sau:

[Conditional(conditionalSymbol)]

Ví dụ:

[Conditional("DEBUG")]

Ví dụ sau đây cho thấy attribute:

#define DEBUG
using System;
using System.Diagnostics;

public class Myclass 
{
   [Conditional("DEBUG")]   
   public static void Message(string msg) 
   {
      Console.WriteLine(msg);
   }
}
class Test 
{
   static void function1() 
   {
      Myclass.Message("In Function 1.");
      function2();
   }
   static void function2() 
   {
      Myclass.Message("In Function 2.");
   }
   public static void Main() 
   {
      Myclass.Message("In Main function.");
      function1();
      Console.ReadKey();
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau

In Main function
In Function 1
In Function 2

Obsolete

Attribute được định nghĩa trước này đánh dấu một thành phần của chương trình không nên được sử dụng. Nó cho phép bạn thông báo cho trình biên dịch để loại bỏ một thành phần đích 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, bạn có thể đánh dấu nó là lỗi thời bằng cách hiển thị một thông báo, nên sử dụng phương thức mới, thay vì phương thức cũ.

Cú pháp để chỉ định attribute này như sau:

[Obsolete(message)]
// or
[Obsolete(message, iserror)]

Ở đây:

  • Tham sốmessage: là một chuỗi mô tả lý do tại sao thành phần bị lỗi thời và sử dụng cái gì để thay thế.
  • Tham số iserror: là một giá trị Boolean. Nếu giá trị của nó là true, trình biên dịch sẽ coi việc sử dụng thành phần là một lỗi. Giá trị mặc định là false (trình biên dịch tạo cảnh báo).

Chương trình sau đây minh họa điều này:

using System;

public class MyClass 
{
   [Obsolete("Don't use OldMethod, use NewMethod instead", true)]   
   static void OldMethod() 
   {
      Console.WriteLine("It is the old method");
   }
   static void NewMethod() 
   {
      Console.WriteLine("It is the new method"); 
   }
   public static void Main() 
   {
      OldMethod();
   }
}

Khi bạn cố gắng biên dịch chương trình, trình biên dịch sẽ đưa ra thông báo lỗi

Don't use OldMethod, use NewMethod instead

Tạo attribute tùy chỉnh

.NET Framework cho phép tạo các attribute tùy chỉnh có thể được sử dụng để lưu trữ thông tin khai báo và có thể được truy xuất tại thời điểm thực thi.

Thông tin này có thể liên quan đến bất kỳ yếu tố mục tiêu nào tùy thuộc vào tiêu chí thiết kế và nhu cầu ứng dụng.

Tạo và sử dụng các attribute tùy chỉnh bao gồm bốn bước:

  • Khai báo một attribute tùy chỉnh
  • Xây dựng attribute tùy chỉnh
  • Áp dụng attribute tùy chỉnh trên một thành phần chương trình.
  • Truy cập các attribute thông qua Reflection.

Bước cuối cùng liên quan đến việc viết một chương trình đơn giản đọc siêu dữ liệu để tìm các ký hiệu khác nhau.

Siêu dữ liệu là dữ liệu hoặc thông tin được sử dụng để mô tả dữ liệu khác. Chương trình này nên sử dụng Reflection để truy cập các attribute trong lúc thực thi. Điều này chúng ta sẽ thảo luận trong chương tiếp theo.

Khai báo một attribute tùy chỉnh

Một attribute tùy chỉnh mới phải được bắt nguồn từ lớp System.Attribute. 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 DebugInfoAttribute : System.Attribute
{}

Trong ví dụ trên, chúng tôi đã khai báo một attribute tùy chỉnh có tên DebugInfoAttribute.

Tip: Tên của attribute nên có hậu tố Attribute để phân biệt với các lớp thông thường.

Xây dựng attribute tùy chỉnh

Chúng tôi sẽ xây dựng một attribute tùy chỉnh có tên DebugInfoAttribute, nơi lưu trữ thông tin thu được bằng cách gỡ lỗi bất kỳ chương trình nào. Nó lưu trữ các thông tin sau:

  • Số mã cho lỗi.
  • Tên của nhà phát triển đã xác định lỗi.
  • Ngày xem xét mã cuối cùng.
  • Nhận xét của nhà phát triển.

Lớp DebugInfoAttribute có ba thuộc tính riêng để lưu trữ ba thông tin đầu tiên và thuộc tính public để lưu trữ nhận xét. Do đó, số lỗi, tên nhà phát triển và ngày xem xét là các tham số vị trí của lớp DebugInfoAttribute và nhận xét là một tham số tùy chọn hoặc được đặt tên.

Mỗi attribute phải có ít nhất một phương thức khởi tạo. Các tham số vị trí nên được truyền qua phương thức khởi tạo. Đoạn mã sau đây cho thấy lớp DebugInfoAttribute:

//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 DebugInfoAttribute : System.Attribute 
{
   private int _bugNo;
   private string _developer;
   private string _lastReview;
   public string _message;
   
   public DebugInfoAttribute(int bg, string dev, string d) 
   {
      _bugNo = bg;
      _developer = dev;
      _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 attribute tùy chỉnh

Attribute được áp dụng bằng cách đặt nó ngay trước thành phần mà bạn mong muốn:

[DebugInfo(45, "Zara Ali", "12/8/2020", Message = "Return type mismatch")]
[DebugInfo(49, "Nuha Ali", "10/10/2019", Message = "Unused variable")]
class Rectangle 
{
   //member variables
   protected double _length;
   protected double _width;
   
   public Rectangle(double l, double w) 
   {
      _length = l;
      _width = w;
   }
   
   [DebugInfo(55, "Zara Ali", "19/04/2020", Message = "Return type mismatch")] 
   public double GetArea() 
   {
      return _length * _width;
   }
   
   [DebugInfo(56, "Zara Ali", "19/10/2019")]   
   public void Display() 
   {
      Console.WriteLine("Length: {0}", _length);
      Console.WriteLine("Width: {0}", _width);
      Console.WriteLine("Area: {0}", GetArea());
   }
}

Trong chương tiếp theo, chúng tôi lấy thông tin attribute bằng cách sử dụng một đối tượng lớp Reflection.

Reflection trong C# | Comdy
Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.


Bài viết liên quan:

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Các tính năng mới của C# 8.0 được Microsoft phát hành cùng với .NET Framework 4.8 và Visual Studio 2019.