1. 程式人生 > >C#基礎系列:Attribute特性使用

C#基礎系列:Attribute特性使用

前言:總結了下反射得基礎用法,這章我們來看看C#的另一個基礎技術——特性。

1、什麼是特性:就博主的理解,特性就是在類的類名稱、屬性、方法等上面加一個標記,使這些類、屬性、方法等具有某些統一的特徵,從而達到某些特殊的需要。比如:方法的異常捕捉,你是否還在某些可能出現異常的地方(例如資料庫的操作、檔案的操作等)經常使用try…catch。這個時候如果使用特性,就可以大大減少方法裡面的try…catch的使用。你只需要定義一個專門捕捉異常的特性類ExceptionExAttribute,然後給這個特性類做些特殊處理,比如給它增加一個AOP攔截的功能(AOP攔截的方式很多,有興趣可以搜搜看,園子裡面很多類似的文章)。那麼在可能出現異常的方法名稱上面加上一個[ExceptionEx]特性標籤,這個方法就具有自動捕捉異常的能力。還是加上官方定義:

特性提供功能強大的方法,用以將元資料或宣告資訊與程式碼(程式集、型別、方法、屬性等)相關聯。 reflection.” data-guid=”716c0768f610f38427afe934e71f1d47″ style=”margin: 0px; padding: 0px;”>特性與程式實體關聯後,即可在執行時使用名為“反射”的技術查詢特性。

特性具有以下屬性:

  • 特性可向程式中新增元資料。 Metadata is information about the types defined in a program.” data-guid=”01e24c05eb8a815d9d031ae958a894ae” style=”margin: 0px; padding: 0px;”>元資料是有關在程式中定義的型別的資訊。 所有的 .NET 程式集都包含指定的一組元資料,這些元資料描述在程式集中定義的型別和型別成員。 可以新增自定義特性,以指定所需的任何附加資訊。
  • 可以將一個或多個特性應用到整個程式集、模組或較小的程式元素(如類和屬性)。
  • 特性可以與方法和屬性相同的方式接受引數。
  • 程式可以使用反射檢查自己的元資料或其他程式內的元資料。

(以上來自MSDN)

2、為什麼需要特性:這個上面已經簡單介紹過,特效能大大減少統一需求的程式碼量。其他不說,至少它能讓我們的程式碼看上去更大氣點吧~~

3、特性的使用:博主這次還是打算從三個方便分別介紹下特性的常規使用方法。當然這幾種方式都是博主原來用過的,可能不是最好的舉例場景,但是也算比較典型的特性用法吧。

(1)類的屬性上面特性的用法:

之所以將這個放在最前面介紹是因為博主最近做的一個BS專案正好用到,並且使用場景也比較典型。首先介紹下使用場景:最近專案有一個需求,BS介面需要一個拖拽的功能。如下圖

c#基礎系列

當將左邊的3個div拖到右邊來時,每個div都有自己的特有屬性,比如2部門拖過來時,要顯示如下屬性:

c#基礎系列

設計思路:每個div對應的Model,每個Model裡面有自己特有的屬性,然後屬性上面加上特性顯示屬性的名稱和預設值,以及介面應該呈現的html標籤。

實現程式碼:

首先來看自定義的一個特性類:

C#
1234567 publicclassDetailAttribute:Attribute{publicstringAttrName{set;get;}publicstringHtml{set;get;}publicstringDefaultValue{set;get;}publicstringDataSource{set;get;}}

對應的Model:

C#
12345678910111213141516171819202122232425262728293031 publicclassFactory{[Detail(AttrName="寬度",Html="<input type='text' />",DefaultValue="50",DataSource=null)]publicstringWidth{set;get;}[Detail(AttrName="高度",Html="<input type='text' />",DefaultValue="50",DataSource=null)]publicstringHeight{set;get;}[Detail(AttrName="狀態",Html="<select></select>",DefaultValue=null,DataSource="select text,value from status")]publicstringStatus{set;get;}[Detail(AttrName="Tag值",Html="<input type='text' />",DefaultValue="",DataSource=null)]publicstringTag{set;get;}}publicclassFactoryDetail{[Detail(AttrName="寬度",Html="<input type='text' />",DefaultValue="50",DataSource=null)]publicstringWidth{set;get;}[Detail(AttrName="高度",Html="<input type='text' />",DefaultValue="50",DataSource=null)]publicstringHeight{set;get;}[Detail(AttrName="狀態",Html="<select></select>",DefaultValue=null,DataSource="select text,value from status")]publicstringStatus{set;get;}[Detail(AttrName="Tag值",Html="<input type='text' />",DefaultValue="",DataSource=null)]publicstringTag{set;get;}[Detail(AttrName="描述",Html="<input type='text' />",DefaultValue="",DataSource=null)]publicstringDesc{set;get;}}

然後在介面的拖放事件結束時通過js傳送ajax請求來得到介面要呈現的html:

XHTML
1234567891011121314151617181920212223242526272829303132 $(".jq-draggable-outcontainer").draggable({helper:"clone",scroll:true,drag:function(event,ui){//debugger;}});$("#content").droppable({drop:function(event,ui){//debugger;if(ui.draggable[0].className.indexOf("jq-draggable-outcontainer") > 0) {                var text = ui.draggable[0].innerText.trim();                $(this).append('<div class="window jq-draggable-incontainer"onclick="GetPropertiesByType(\'1\',this)"style="position:absolute;left:' +(event.clientX-20) + 'px;top:' + (event.clientY-20) + 'px"id="window' + iIndex + '"><strong>' + text + '</strong></div>');                $("#content2").html("");                cur_selector = $("#window"+iIndex);                $.Ewin.AjaxPost("/Home/GetModelByType", { strType: "Factory" }, function (data, status) {                    var element = $.parseJSON(data.Json);                    var arrProp = element.element.property;                    //0.構造html                    var strHtml = "<div style='float:right;padding-top:0px;width:300px;height:auto;'><table cellpadding='5'border='1'>";                    //1.拼html構造屬性                    strHtml += "</table></div>";                    $("#content2").append(strHtml);},function(){},null);iIndex++;}}});

對應的C#方法:

C#
1234567891011121314151617181920212223242526272829 publicJsonResult GetModelByType(stringstrType){       //strType傳過來的是Factory或者FactoryDetailvarassembly=Assembly.Load("Ewin.Client.Web");//引數為程式集的名稱varoType=assembly.GetType("Ewin.Client.Web.Controllers."+strType);      //得到類的所有屬性varlstProperties=oType.GetProperties();foreach(varoProperty inlstProperties){        //得到每一個屬性的特性類集合IList<CustomAttributeData>lstAttr=oProperty.GetCustomAttributesData();foreach(varoAttr inlstAttr){            //得到每一個特性類的全稱Console.WriteLine("特性類的名稱"+oAttr.AttributeType.FullName);Console.WriteLine("特性類成員如下:");            //得到特性類的所有引數varlstAttrArgu=oAttr.NamedArguments;foreach(varoAttrAru inlstAttrArgu){              //取每個特性類引數的鍵值對Console.WriteLine(oAttrAru.MemberName+"="+oAttrAru.TypedValue.Value);}//Console.WriteLine(oAttr.AttributeType+"——"+oAttr.NamedArguments);}}returnJson(new{},JsonRequestBehavior.AllowGet);}

GetModelByType方法結果簡單構造下然後將屬性的鍵值對返回給js方法,然後再由js追加到介面上面。這樣通過特性和反射的結合能很快完成這個小功能的設計。

(2)類的方法上面特性的用法:

這個用法.Net framework裡面就很多,如果MVC裡面Filter過濾器的用法:

C#
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 publicclassSuperLogStat:ActionFilterAttribute{//模組名稱privateEnumModuleName moduleEnum=EnumModuleName.ModuleOther;//功能名稱privatestringfunctionName=string.Empty;//使用者IdprivatestringuserId=string.Empty;publicstringVersion{get{returnConfigurationManager.AppSettings["UploatStatVersion"];}}publicEnumModuleNameModuleEnum{get{returnthis.moduleEnum;}set{this.moduleEnum=value;}}publicstringFunctionName{get{returnthis.functionName;}set{this.functionName=value;}