文章內容參考了nuaaflm的反射學習系列2-特性(Attribute),鏈接地址為:http://www.cnblogs.com/nuaalfm/archive/2008/09/07/1286195.html
因為打算寫一個簡單的ORM實現,所以上網上參考了些資料,現在先介紹一下需要用到的一個重要的技術,特性(Attribute)。因為原文的作者已經介紹得很詳細了,我就不自己寫了,直接COPY過來。由於原作者使用的是.net3.5的,我把代碼改成了2.0的版本。
先看一個簡單的例子
[Table(Name="UserInfo")]
public class UserInfo
{
當C#編譯器發現這個屬性有一個特性Table時,首先會把字符串Attribute添加到這個名稱的後面,形成一個組合名稱TableAttribute,然後在其搜索路徑的所有命名空間中搜索有相同類名的類。但要注意,如果該特性名結尾是Attribute,編譯器就不會把該字符串加到組合名稱中。所有的特性都是從System.Attribute類型上面派生的。
接著我們來看一下Table特性的定制格式
[AttributeUsageAttribute(AttributeTargets.Class, Inherited=true,AllowMultiple=false)]
public class TalbeAttribute:Attribute
{
在定義類型時使用System.AttributeUsage特性來表明這個自定義特性的使用范圍,這裡使用了Class樣式,表示TableAttribute特性只能用在其它的Class類型前面,若放置在Interface或Struct類型前面,或者放在對象成員的前面則會出現編譯錯誤。這裡還是用語句 AllowMultiple=false 語句來表明對於一個類型,該特性只能用一次,若一個Class類型前面出現多個TableAttribute,則會出現編譯錯誤。若設置AllowMultiple=true,則該特性可以多次定義,也就是一個Class類型前面可以出現多個相同類型的特性。不過這裡我們假設一個對象只能映射到一個數據表上,沒有多重映射,因此就指明對同一個類型該特性不能多次使用。Inherited參數設定為true,就表示應用到類或接口上的特性也可以自動應用到所派生的類或接口上。
我們再看一下定制TalbeAttribute特性的完整例子:
Code
[AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=false)]
public class TableAttribute : Attribute
{
private string tableName;
public string TableName
{
get { return tableName; }
set { tableName = value; }
}
public TableAttribute()
{
this.tableName = null;
}
public TableAttribute(string tableName)
{
this.tableName = tableName;
}
}
特性也是一個Class類型,可以有多個構造函數,就像C#的new語句一樣,我們向類型附加特性時可以使用不同的初始化參數來指明使用特性的那個構造函數。我們附加特性時還可以使用“屬性名=屬性值”的方法來直接指明特性的屬性值。該特性中定義了一個TableName屬性,該屬性就是被修飾的對象所映射的數據庫表的名稱。
下面我們舉一個使用特性來進行O/RMapping的例子
用戶類:
Code
[Table("UserInfo")]
public class UserInfo
{
private int userId;
[Column("UserId",DbType.Int32)]
public int UserId
{
get { return userId; }
set { userId = value; }
}
private string userName;
[Column(UserName,DbType.String)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
}
列特性:
Code
[AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=false)]
public class ColumnAttribute : Attribute
{
public ColumnAttribute()
{
this.columnName = null;
this.dbType = DbType.String;
}
public ColumnAttribute(string columnName)
{
this.columnName = columnName;
}
public ColumnAttribute(string columnName, DbType dbType)
: this(columnName)
{
this.dbType = dbType;
}
private string columnName;
public string ColumnName
{
get { return columnName; }
set { columnName = value; }
}
private DbType dbType;
public DbType DbType
{
get { return dbType; }
set { dbType = value; }
}
}
運行類:
Code
class Program
{
static void Main(string[] args)
{
UserInfo userInfo = new UserInfo();
Type type = userInfo.GetType();
TableAttribute ta = (TableAttribute)type.GetCustomAttributes(false)[0];
Console.WriteLine("數據表名:" + ta.TableName);
PropertyInfo[] infos = type.GetProperties();
foreach (PropertyInfo info in infos)
{
object[] attributes = info.GetCustomAttributes(false);
foreach (object att in attributes)
{
if (att is ColumnAttribute)
{
ColumnAttribute ca = att as ColumnAttribute;
string cn = ca.ColumnName == null ? info.Name : ca.ColumnName;
Console.WriteLine("字段名:" + cn);
Console.WriteLine("字段類型:" + ca.DbType);
}
}
}
}
下面是運行結果的截圖: