首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> C# 入門

全面認識 C#(十五):屬性 - 編譯期中繼資料與執行期反射

     編輯:C# 入門

前言

屬性 讓開發者在程式碼中嵌入宣告式中繼資料,編譯進組件,執行期透過反射讀取。廣泛用於序列化、驗證、條件編譯、框架擴展點等場景。

基本語法


[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class AuthorAttribute : Attribute {
    public string Name { get; }
    public string Email { get; set; } // 可選位置參數/命名參數
    public AuthorAttribute(string name) => Name = name;
}

// 使用
[Author("Ben Albahari", Email = "ben@example.com")]
public class MyClass {
    [Obsolete("Use NewMethod()", true)] // 編譯器警告/錯誤
    public void OldMethod() { }

    [Conditional("DEBUG")] // 僅 DEBUG 編譯時保留呼叫
    public void DebugLog(string msg) { }
}

預定義重要屬性

屬性用途目標
Obsolete標記過時 API,編譯器警告/錯誤所有
Conditional條件編譯方法呼叫方法
Serializable標記可序列化類別類別/結構
AttributeUsage限制屬性適用目標、可重複性、繼承性屬性類別
CallerMemberName自動填入呼叫端成員名稱參數
CallerFilePath自動填入呼叫端檔案路徑參數
CallerLineNumber自動填入呼叫端行號參數

執行期反射讀取


var attrs = typeof(MyClass).GetCustomAttributes(inherit: true);
foreach (var attr in attrs) {
    Console.WriteLine($"Author: {attr.Name}, Email: {attr.Email}");
}

// 方法屬性
var method = typeof(MyClass).GetMethod("OldMethod");
var obsolete = method.GetCustomAttribute();
if (obsolete != null) Console.WriteLine($"Obsolete: {obsolete.Message}");

實務應用場景

1. 模型驗證 (Data Annotations)


public class User {
    [Required]
    [StringLength(50, MinimumLength = 2)]
    public string Name { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Range(18, 120)]
    public int Age { get; set; }
}

// 驗證
var context = new ValidationContext(user);
var results = new List();
bool valid = Validator.TryValidateObject(user, context, results, true);

2. XML/JSON 序列化控制


public class Person {
    [JsonPropertyName("full_name")]
    [XmlElement("Name")]
    public string Name { get; set; }

    [JsonIgnore]
    [XmlIgnore]
    public string InternalId { get; set; }

    [JsonConverter(typeof(UnixTimestampConverter))]
    public DateTime BirthDate { get; set; }
}

3. 依賴注入/服務註冊


[ServiceLifetime(ServiceLifetime.Scoped)]
public interface IUserService { }

[AttributeUsage(AttributeTargets.Class)]
public class ServiceLifetimeAttribute : Attribute {
    public ServiceLifetime Lifetime { get; }
    public ServiceLifetimeAttribute(ServiceLifetime lifetime) => Lifetime = lifetime;
}

4. 單元測試標記


[TestClass]
public class CalculatorTests {
    [TestMethod]
    [DataRow(1, 2, 3)]
    [DataRow(-1, 1, 0)]
    public void Add_Test(int a, int b, int expected) {
        Assert.AreEqual(expected, a + b);
    }

    [TestMethod]
    [ExpectedException(typeof(DivideByZeroException))]
    public void DivideByZero_Test() { 1 / 0; }
}

自訂屬性最佳實務

  1. 繼承 System.Attribute
  2. 加上 AttributeUsage 限制目標
  3. 建構子參數為位置參數 (必填),屬性為命名參數 (選填)
  4. 屬性類別密封 sealed (除非設計為基底)
  5. 避免屬性邏輯複雜,僅作為中繼資料標記

Java 註解對比

特性C# AttributeJava Annotation
語法[Attribute]@Annotation
編譯輸出編譯進 IL 中繼資料可選擇 SOURCE/CLASS/RUNTIME 保留策略
參數類型基本型別、Type、enum、陣列類似,支援預設值
繼承AttributeUsage(Inherited=true)@Inherited
條件編譯ConditionalAttribute無直接對應

總結

屬性是 C# 宣告式程式設計的核心機制,將中繼資料從程式邏輯分離,編譯期嵌入、執行期反射讀取。善用預定義屬性 (Obsolete, Conditional, DataAnnotations) 並設計自訂屬性,能構建極具擴展性的框架與工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved