程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 中特性(Attribute)的使用簡介

C# 中特性(Attribute)的使用簡介

編輯:C#入門知識

 

Attribute(特性)

MSDN給出的定義:

Attribute 類將預定義的系統信息或用戶定義的自定義信息與目標元素相關聯。目標元素可以是程序集、類、構造函數、委托、枚舉、事件、字段、接口、方法、可移植可執行文件模塊、參數、屬性(Property)、返回值、結構或其他特性(Attribute)。

在.Net程序中,可以使用特性(Attribute)來解決許多問題。如:將WebService中接口函數標記為WebMethod,將類標記為可序列化等等。

 

此外,我們也可以自定義Attribute,來實現我們需要的功能。但自定義Attribute必須繼承自Attribute類。Attribute中有很多方法或者屬性,為我們提供了強大的功能。一般我們通過反射的方式來使用Attribute。

 

下面結合實際項目中的使用談談自己的體會。

需求:項目中有一個專門的日志庫。現在項目中需要前端用到查詢、翻頁、按各個字段排序等等功能。由於日志數據可能有無效的數據,並且數據量較大。為了提升統計、翻頁性能,所以建立了許多臨時表。如果在實際操作中為一個一個不同的需求去建立臨時表,造成代碼大量重復臃腫,並且不便於統一管理,考慮到的方案是通過Attribute的方式,統一建臨時表。

主體思路如下:通過自定義特性來描述要建立臨時表的字段的相關類型、長度等等信息,然後通過反射的方式獲取這些字段對應的這些特性,然後構造相應的SQL命令就可以完成臨時表的建立了。

特性定義如下:

[AttributeUsage(AttributeTargets.Property)]

public class TableFieldAttribute : Attribute

{

/// <summary>

/// 字段長度

/// </summary>

public int Length { get; set; }

 

/// <summary>

/// 字段描述

/// </summary>

public string Describe { get; set; }

 

/// <summary>

/// 字段類型

/// </summary>

public string Type { get; set; }

 

}

以上AttributeUsage,也是一個繼承自Attribute的類,他的作用就是標志自定義類的使用范圍,如:字段,屬性,類,方法。以及使用我們自定義類

標記的類的子類是否繼承特性等。

有了這個自定義特性,將它運用到實體上就行了。

public class TableEntity

{

[TableField(Describe = "Guid主鍵", Length = 36, Type = "uniqueidentifier")]

public Guid Guid { get; set; }

 

[TableField(Describe = "名稱", Length = 36, Type = "varchar ")]

public string Name { get; set; }

}

這樣在實體定義上,我們就已經有了定義好了數據類型,長度等等。在實際要建臨時表時,通過反射要建臨時表的實體,便能構造相應的SQL命令了。

 

工具類的定義:public class Tools<T> where T : class。實際使用時,將泛型類型換成相應的類型即可。

主要給出如何使用反射來獲取臨時表具體字段的信息代碼:

public static List<Record> GetTableFieldsInformation()

{

Type t = typeof(T);

PropertyInfo[] propertyInfos = t.GetProperties();

List<Record> tableEntities = new List<Record>();

propertyInfos.ToList().ForEach(property =>

{

IList<CustomAttributeData> list = property.GetCustomAttributesData();

if (list.Count == 1)

{

tableEntities.Add(GetTableEntity(list[0].NamedArguments, property));

}

else

{

throw new Exception();

}

});

return tableEntities;

}

這樣,GetTableFieldsInformation()方法中返回的List就是包含了臨時表一個字段的所有信息的列表。我們循環列表,構造Sql命令

主要代碼如下:

recordEntities.ForEach(record =>

{

if (i == 0)

{

sql = "CREATE TABLE [" + record.TableName + "](";

}

if (list.All(item => !record.Type.Equals(item, StringComparison.OrdinalIgnoreCase)))

{

sql += string.Format("{0} {1}({2}),", record.FieldName, record.Type, record.Length);

}

else

{

sql += string.Format("{0} {1},", record.FieldName, record.Type);

}

i++;

});

 

程序最終執行後如下圖:

 

 

\

 

 

主要的思想就是這些。另外,如果你細心,你會發現AttributeUsage特性使用和我定義的TableFieldAttribute使用方式上有寫不一樣。

TableFieldAttribute的使用方式:[TableField(Describe = "Guid主鍵", Length = 36, Type = "uniqueidentifier")]

AttributeUsage的使用方式:[AttributeUsage(AttributeTargets.Property)]。

同樣是自定義的特性,為什麼我們定義的和Framework庫裡的使用不一樣呢。?通過Reflect看看AttributeUsage的源碼,如下圖:

 

 

\

 

從圖中標記的地方來看,是由於在AttributeUsage中屬性的定義【AttributeTargets ValidOn】以及構造函數的定義不一樣導致的。

有興趣深入研究的同學可以自己試試。

 

後記:特性的使用是很強大的一項功能。本例中使用的僅僅是其他很小的一部分。因此只對在實際應用中做了寫說明。另:代碼是沒有經過細致整理

 

代碼下載:http://www.BkJia.com/uploadfile/2011/1025/20111025113636140.rar

摘自:tyb1222

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved