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

C# Attribute 特性深度解析:從定義到 ORM 映射實戰

     編輯:關於C#

特性是什麼?

特性 是附加在程式碼元素 (類、屬性、方法...) 上的宣告式中繼資料。編譯器將其編入組件元數據,運行時透過反射讀取,驅動序列化、驗證、ORM 映射、DI 容器等框架行為。

特性定義構造

[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class TableAttribute : Attribute
{
    private string _tableName;
    public TableAttribute() { }
    public TableAttribute(string tableName) => _tableName = tableName;

    public string TableName 
    { 
        get => _tableName; 
        set => _tableName = value; 
    }
}

關鍵屬性解析

  • AttributeTargets.Class:只能用於類;可用 Property、Method、All 等
  • Inherited:子類是否繼承此特性
  • AllowMultiple:同一目標是否可重複套用
  • 命名慣例:類名以 Attribute 結尾,使用時可省略 (如 [Table] 等同 [TableAttribute])

完整 ORM 映射範例

1. 定義實體與特性

[Table("Users")]
public class User
{
    [Column("UserID", DbType = DbType.Int32)]
    public int UserID { get; set; }

    [Column("UserName", DbType = DbType.String)]
    public string UserName { get; set; }
}

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ColumnAttribute : Attribute
{
    public string ColumnName { get; set; }
    public DbType DbType { get; set; }
    public ColumnAttribute(string name) => ColumnName = name;
}

2. ORM 輔助類:反射讀取特性生成 SQL

public class OrmHelper
{
    public void Insert(object entity)
    {
        Type type = entity.GetType();
        var tableAttr = type.GetCustomAttributes(typeof(TableAttribute), false)
                            .FirstOrDefault() as TableAttribute;
        if (tableAttr == null) throw new InvalidOperationException("缺少 TableAttribute");

        var sb = new StringBuilder($"INSERT INTO {tableAttr.TableName} (");
        var props = type.GetProperties();
        var columns = new List<string>();
        var values = new List<string>();

        foreach (var prop in props)
        {
            var colAttr = prop.GetCustomAttributes(typeof(ColumnAttribute), false)
                              .FirstOrDefault() as ColumnAttribute;
            if (colAttr == null) continue; // 忽略無標記屬性

            columns.Add(colAttr.ColumnName);
            object val = prop.GetValue(entity);
            values.Add(val == null ? "NULL" : FormatValue(val, colAttr.DbType));
        }

        sb.Append(string.Join(",", columns));
        sb.Append(") VALUES (");
        sb.Append(string.Join(",", values));
        sb.Append(")");

        Console.WriteLine(sb.ToString());
        // 實際專案這裡執行 DbCommand
    }

    private string FormatValue(object val, DbType dbType)
    {
        return dbType == DbType.String ? $"'{val}'" : val.ToString();
    }
}

3. 使用示例

var helper = new OrmHelper();
var user = new User { UserID = 1, UserName = "lfm" };
helper.Insert(user);
// 輸出: INSERT INTO Users (UserID,UserName) VALUES (1,'lfm')

進階:多構造函數與命名參數

[Column("Email", DbType = DbType.String)]
public string Email { get; set; }

// 等同於
[Column("Email")] 
public string Email { get; set; } // DbType 走預設

常見內建特性速查

特性用途命名空間
[Obsolete]標記過時成員System
[Serializable]標記可序列化類型System
[Conditional("DEBUG")]條件編譯方法System.Diagnostics
[CallerMemberName]自動獲取調用者名稱System.Runtime.CompilerServices
[Key]EF 主鍵標記System.ComponentModel.DataAnnotations

最佳實踐

  1. 特性類保持輕量:只存中繼資料,不含業務邏輯
  2. 讀取端緩存反射結果:啟動時掃描組裝緩存,運行期直接讀緩存
  3. 善用繼承:Inherited = true 讓基類特性自動流向子類
  4. 文檔化目標範圍:明確 AttributeTargets 防止誤用

特性是框架與應用代碼的契約語言,掌握它能讓你讀懂主流框架源碼,也能打造屬於自己的微型框架。

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