C# 是命令式語言,但通過屬性 實現聲明性編程擴展:程序員定義屬性類型,附加到程序實體 (類、方法、屬性、參數、程序集等),運行時通過反射檢索。本文對應規范第 1.14 節 (及第 17 章)「屬性」。
using System;
[AttributeUsage(AttributeTargets.All)] // 指定可應用目標
public class HelpAttribute : Attribute
{
// 位置參數:構造函數參數
public HelpAttribute(string url)
{
this.Url = url;
}
// 命名參數:公共非靜態字段/屬性
public string Topic = null; // 字段形式
public string Url { get; } // 唯讀屬性形式
// 可添加其他實例字段/屬性/方法
}
// 類級別:僅位置參數
[Help("https://docs.example.com/Class1.htm")]
public class Class1
{
// 方法級別:位置參數 + 命名參數
[Help("https://docs.example.com/Class1.htm", Topic = "F")]
public void F() { }
}
using System;
class Test
{
static void Main()
{
Type type = typeof(Class1);
// 獲取類級別屬性 (inherit=true 搜尋繼承鏈)
object[] attrs = type.GetCustomAttributes(typeof(HelpAttribute), true);
if (attrs.Length == 0)
{
Console.WriteLine("Class1 has no Help attribute.");
}
else
{
HelpAttribute ha = (HelpAttribute)attrs[0];
Console.WriteLine($"Url = {ha.Url}, Topic = {ha.Topic}");
}
// 獲取方法級別屬性
var method = type.GetMethod("F");
var methodAttrs = method.GetCustomAttributes(true);
foreach (var ma in methodAttrs)
Console.WriteLine($"Method F: Url={ma.Url}, Topic={ma.Topic}");
}
}
| API | 用途 | 關鍵參數 |
|---|---|---|
| `MemberInfo.GetCustomAttributes(Type, inherit)` | 獲取指定類型屬性 (返回 object[]) | `inherit`: 是否搜尋繼承鏈 |
| `MemberInfo.GetCustomAttributes | 泛型版本,直接返回 T[] | 同上 |
| `Attribute.GetCustomAttribute(MemberInfo, Type)` | 靜態方法,獲取單個 (多個拋異常) | |
| `Attribute.IsDefined(MemberInfo, Type, inherit)` | 快速判斷是否應用 | |
| `Assembly.GetCustomAttributes()` | 程序集級屬性 (如 AssemblyVersion, AssemblyTitle) |
// AllowMultiple=true 允許同一目標多次應用
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AuthorAttribute : Attribute
{
public string Name { get; }
public AuthorAttribute(string name) => Name = name;
}
[Author("Alice")]
[Author("Bob")] // 合法
public class MyClass { }
屬性是 C# 類型系統的「標籤系統」,將聲明性元數據與代碼結構綁定,運行時通過反射賦能:序列化控制、驗證規則、依賴注入標記、代碼生成指令、測試框架發現、編譯器指導 等無數框架機制的基石。掌握 `AttributeUsage`、位置/命名參數、反射檢索、內置屬性、密封設計,是從「使用框架」走向「構建框架」的關鍵能力。