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

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

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

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

特性提供功能強大的方法,用以將元資料或宣告資訊與程式碼(程式集、型別、方法、屬性等)相關聯。 特性與程式實體關聯後,即可在執行時使用名為“反射”的技術查詢特性。

特性具有以下屬性:

  • 特性可向程式中新增元資料。 元資料是有關在程式中定義的型別的資訊。 所有的 .NET 程式集都包含指定的一組元資料,這些元資料描述在程式集中定義的型別和型別成員。 可以新增自定義特性,以指定所需的任何附加資訊。 

  • 可以將一個或多個特性應用到整個程式集、模組或較小的程式元素(如類和屬性)。

  • 特性可以與方法和屬性相同的方式接受引數。

  • 程式可以使用反射檢查自己的元資料或其他程式內的元資料。

       (以上來自MSDN)

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

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

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

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

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

1和3部門拖過來時可能對應的屬性不同。

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

實現程式碼:

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

   public class DetailAttribute : Attribute
    {
        public string AttrName { set; get; }
        public string Html { set; get; }
        public string DefaultValue { set; get; }
        public string DataSource { set; get; }
    }

對應的Model:

   public class Factory
    {
        [Detail(AttrName="寬度", Html="<input type='text' />", DefaultValue="50", DataSource=null)]
        public string Width { set; get; }

        [Detail(AttrName = "高度", Html = "<input type='text' />", DefaultValue = "50", DataSource = null)]
        public string Height { set; get; }

        [Detail(AttrName = "狀態", Html = "<select></select>", DefaultValue = null, DataSource = "select text,value from status")]
        public string Status { set; get; }

        [Detail(AttrName = "Tag值", Html = "<input type='text' />", DefaultValue = "", DataSource = null)]
        public string Tag { set; get; }
    }

    public class FactoryDetail
    {
        [Detail(AttrName = "寬度", Html = "<input type='text' />", DefaultValue = "50", DataSource = null)]
        public string Width { set; get; }

        [Detail(AttrName = "高度", Html = "<input type='text' />", DefaultValue = "50", DataSource = null)]
        public string Height { set; get; }

        [Detail(AttrName = "狀態", Html = "<select></select>", DefaultValue = null, DataSource = "select text,value from status")]
        public string Status { set; get; }

        [Detail(AttrName = "Tag值", Html = "<input type='text' />", DefaultValue = "", DataSource = null)]
        public string Tag { set; get; }
        [Detail(AttrName = "描述", Html = "<input type='text' />", DefaultValue = "", DataSource = null)]
        public string Desc { set; get; }
    }

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

$(".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#方法:

     public JsonResult GetModelByType(string strType)
        {
       //strType傳過來的是Factory或者FactoryDetail
var assembly = Assembly.Load("Ewin.Client.Web");//引數為程式集的名稱 var oType = assembly.GetType("Ewin.Client.Web.Controllers." + strType);
       //得到類的所有屬性
var lstProperties = oType.GetProperties(); foreach (var oProperty in lstProperties) {
         //得到每一個屬性的特性類集合 IList
<CustomAttributeData> lstAttr = oProperty.GetCustomAttributesData(); foreach (var oAttr in lstAttr) {
            //得到每一個特性類的全稱 Console.WriteLine(
"特性類的名稱" + oAttr.AttributeType.FullName); Console.WriteLine("特性類成員如下:");
            //得到特性類的所有引數
var lstAttrArgu = oAttr.NamedArguments; foreach (var oAttrAru in lstAttrArgu) {
              //取每個特性類引數的鍵值對 Console.WriteLine(oAttrAru.MemberName
+ "=" + oAttrAru.TypedValue.Value); } //Console.WriteLine(oAttr.AttributeType+"——"+oAttr.NamedArguments); } } return Json(new { }, JsonRequestBehavior.AllowGet); }

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

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

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

public class SuperLogStat : ActionFilterAttribute
    {
        //模組名稱
        private EnumModuleName moduleEnum = EnumModuleName.ModuleOther;
        //功能名稱
        private string functionName = string.Empty;
        //使用者Id
        private string userId = string.Empty;
        
        public string Version
        {
            get { return ConfigurationManager.AppSettings["UploatStatVersion"]; }
        }

        public EnumModuleName ModuleEnum
        {
            get { return this.moduleEnum; }
            set { this.moduleEnum = value; }
        }

        public string FunctionName
        {
            get { return this.functionName; }
            set { this.functionName = value; }
        }

  

     //這兩個方法都是父類的virtual方法,一個再return View()之前執行,一個再之後執行
        //
        // 摘要:
        //     在執行操作方法之前由 MVC 框架呼叫。
        //
        // 引數:
        //   filterContext:
        //     篩選器上下文。
        public override void OnActionExecuting(ActionExecutingContext filterContext) 
        {
            try
            {
                string userName = filterContext.HttpContext.User.Identity.Name;
                this.userId = userName.Replace("china\\", "");
            }
            catch (Exception)
            {
                this.userId = string.Empty;
            }
        }
        
        //
        // 摘要:
        //     在執行操作結果之前由 MVC 框架呼叫。
        //
        // 引數:
        //   filterContext:
        //     篩選器上下文。
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            UserLogUtils.LogUserStatic(this.userId, this.Version,
                EnumUtils.getEnumDescByValue((int)this.moduleEnum, typeof(EnumModuleName)),
                this.functionName);
        }

    }
View Code

在Controller裡面方法上面加上特性:

//呼叫

[SuperLogStat(ModuleEnum = EnumModuleName.ModuleHome, FunctionName = "待稽核")]

        public ActionResult MyApplyToAuditing()
        {
            return View();
        }

這個ActionFilterAttribute這個特性用法裡面就有異常的攔截機制,和前面說的自定義的異常攔截是相同的。

(3)類上面特性的用法:

類上面特性的用法其實.Net裡面也很多。比如為了避免new一個物件而使用的MEF就是一個很有說服力的例子:

在定義個類實現一個介面時:

    [Export("Impc_TB_Test", typeof(Ifc_TB_Test))]
    public class Impc_TB_Test : Ifc_TB_Test
    {
        ......
    }    

定義介面沒有任何特殊:

    public interface Ifc_TB_Test
    {
        ......
    }

然後在使用時只需要加一個[Import]標籤,這個變數就會在編譯時自動new一個Impc_TB_Test變數:

[Import("Impc_TB_Test")]
 Ifc_TB_Test service { get; set; }

在使用service變數時,就可以直接把它當做一個Impc_TB_Test物件來使用。是不是很方便。

這幾種常見用法都是博主用過的覺得比較好的場景,當然特性的用法肯定遠不止如此,歡迎大俠們指正拍磚~~

相關推薦

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

前言:上篇 C#基礎系列——反射筆記 總結了下反射得基礎用法,這章我們來看看C#的另一個基礎技術——特性。 1、什麼是特性:就博主的理解,特性就是在類的類名稱、屬性、方法等上面加一個標記,使這些類、屬性、方法等具有某些統一的特徵,從而達到某些特殊的需要。比如:方法的異常捕捉,你是否還在某些可能出現異常的地方

C#基礎系列Attribute特性使用

前言:總結了下反射得基礎用法,這章我們來看看C#的另一個基礎技術——特性。 1、什麼是特性:就博主的理解,特性就是在類的類名稱、屬性、方法等上面加一個標記,使這些類、屬性、方法等具有某些統一的特徵,從而達到某些特殊的需要。比如:方法的異常捕捉,你是否還在某些可能出現

c#基礎系列3---深入理解ref 和out

ref 聲明 函數的參數 .... -- 新增 tel struct 結果 “大菜”:源於自己剛踏入猿途混沌時起,自我感覺不是一般的菜,因而得名“大菜”,於自身共勉。 擴展閱讀 c#基礎系列1---深入理解 值類型和引用類型 c#基礎系列2---深入理解 Str

C#基礎系列:非同步程式設計初探async和await

前言:前面有篇從應用層面上面介紹了下多執行緒的幾種用法,有博友就說到了async, await等新語法。確實,沒有非同步的多執行緒是單調的、乏味的,async和await是出現在C#5.0之後,它的出現給了非同步並行變成帶來了很大的方便。非同步程式設計涉及到的東西還

C#基礎系列:序列化效率比拼

      前言:作為開發人員,物件的序列化恐怕難以避免。樓主也是很早以前就接觸過序列化,可是理解都不太深刻,對於用哪種方式去做序列化更是隨波逐流——專案中原來用的什麼方式照著用就好了。可是這麼多年自己對於這東西還是挺模糊的,今天正好有時間,就將原來用過的幾種方式總結了下,也算是做一個記錄,順便做了下效能測

C#基礎系列:反射筆記

前言:使用反射也有幾年了,但是一直覺得,反這個概念很抽象,今天有時間就來總結下這個知識點。 1、為什麼需要反射: 最初使用反射的時候,作為小菜總是不理解,既然可以通過new 一個物件的方式得到物件,然後通過物件去呼叫屬性和方法,那麼為什麼還需要反射去呼叫呢?後來使用

C#基礎系列:委託實現簡單設計模式(1)

前言:這篇簡單介紹下委託的使用。當然啦,園子裡面很多介紹委託的文章都會說道:委託和事件的概念就像一道坎,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委託和事件就覺得心裡發慌。確實這東西就像最開始學C語言的指標一樣,令人有一種很糾結的感覺,總覺得要呼叫一個

C#基礎系列:委託和設計模式(2)

前言:這篇打算從設計模式的角度去解析下委託的使用。我們知道使用委託可以實現物件行為(方法)的動態繫結,從而提高設計的靈活性。上次說過,方法可以理解為委託的例項,站在方法的層面,委託例項的一個非常有用的特性是它既不知道,也不關心其封裝方法所屬類的詳細資訊,對它來說最重

C#基礎系列:再也不用擔心面試官問我“事件”了

前言:作為.Net攻城獅,你面試過程中是否遇到過這樣的問題呢:什麼是事件?事件和委託的區別?既然事件作為一種特殊的委託,那麼它的優勢如何體現?諸如此類…你是否也曾經被問到過?你又是否都答出來了呢? 關於面試中涉及到的事件的問題,我們只需要抓住幾個關鍵點就好了: (1

C#基礎系列:小話泛型

前言:這一章來總結下C#泛型技術的使用。據博主的使用經歷,覺得泛型也是為了重用而生的,並且大部分時候會和反射一起使用。這次還是打算圍繞WWH(即What、Why、How)來講解。 1、什麼是泛型:通過引數化型別來實現在同一份程式碼上操作多種資料型別。利用“引數化型別

C#基礎系列:擴充套件方法的使用

前言:打算分三個層面來介紹這個知識點,分別是:.Net內建物件的擴充套件方法、一般物件的擴充套件方法、泛型物件的擴充套件方法。 什麼是擴充套件方法?回答這個問題之前,先看看我們一般情況下方法的呼叫。類似這樣的通用方法你一定寫過:

C#基礎系列:Linq to Xml讀寫xml

前言:xml的操作方式有多種,但要論使用頻繁程度,博主用得最多的還是Linq to xml的方式,覺得它使用起來很方便,就用那麼幾個方法就能完成簡單xml的讀寫。之前做的一個專案有一個很變態的需求:C#專案呼叫不知道是什麼語言寫的一個WebService,然後新增服

C#基礎系列:多執行緒的常見用法詳解

前言:此篇就主要從博主使用過的幾種多執行緒的用法從應用層面大概介紹下。文中觀點都是博主個人的理解,如果有不對的地方望大家指正~~ 1、多執行緒:使用多個處理控制代碼同時對多個任務進行控制處理的一種技術。據博主的理解,多執行緒就是該應用的主執行緒任命其他多個執行緒去協

C#基礎系列——委託實現簡單設計模式

前言:上一篇介紹了下多執行緒的相關知識:C#基礎系列——多執行緒的常見用法詳解,裡面就提到了委託變數。這篇簡單介紹下委託的使用。當然啦,園子裡面很多介紹委託的文章都會說道:委託和事件的概念就像一道坎,過了這個檻的人,覺得真是太容易了,而沒有過去的人每次見到委託和事件就覺得心裡發慌。確實這東西就像最開始學C語言

C#基礎系列——多執行緒的常見用法詳解

前言:前面幾節分別介紹了下C#基礎技術中的反射、特性、泛型、序列化、擴充套件方法、Linq to Xml等,這篇跟著來介紹下C#的另一基礎技術的使用。最近專案有點緊張,所以準備也不是特別充分。此篇就主要從博主使用過的幾種多執行緒的用法從應用層面大概介紹下。文中觀點都是博主個人的理解,如果有不對的地方望大家指正

C#基礎系列——小話泛型

前言:前面兩章介紹了C#的兩個常用技術:C#基礎系列——反射筆記 和 C#基礎系列——Attribute特性使用 。這一章來總結下C#泛型技術的使用。據博主的使用經歷,覺得泛型也是為了重用而生的,並且大部分時候會和反射一起使用。這次還是打算圍繞WWH(即What、Why、How)來講解。 1、什麼是泛型

C#基礎系列——再也不用擔心面試官問我“事件”了

前言:作為.Net攻城獅,你面試過程中是否遇到過這樣的問題呢:什麼是事件?事件和委託的區別?既然事件作為一種特殊的委託,那麼它的優勢如何體現?諸如此類...你是否也曾經被問到過?你又是否都答出來了呢?上兩篇由淺及深介紹了下委託的用法,這篇還是來說說事件。希望通過這篇的介紹,博友能有個系統的認識,至少應付面試沒

C#基礎系列——反射筆記

前言:使用反射也有幾年了,但是一直覺得,反這個概念很抽象,今天有時間就來總結下這個知識點。 1、為什麼需要反射:   最初使用反射的時候,作為小菜總是不理解,既然可以通過new 一個物件的方式得到物件,然後通過物件去呼叫屬性和方法,那麼為什麼還需要反射去呼叫呢?後來使用多了發現這就是一個先繫結還是後繫

C#基礎系列——委託和設計模式(二)

前言:前篇 C#基礎系列——委託實現簡單設計模式 簡單介紹了下委託的定義及簡單用法。這篇打算從設計模式的角度去解析下委託的使用。我們知道使用委託可以實現物件行為(方法)的動態繫結,從而提高設計的靈活性。上次說過,方法可以理解為委託的例項,站在方法的層面,委託例項的一個非常有用的特性是它既不知道,也不關心其封裝

C#基礎系列——一場風花雪月的邂逅:介面和抽象類

前言:最近一個認識的朋友準備轉行做程式設計,看他自己邊看視訊邊學習,挺有幹勁的。那天他問我介面和抽象類這兩個東西,他說,既然它們如此相像, 我用抽象類就能解決的問題,又整個接口出來幹嘛,這不是誤導初學者嗎。博主呵呵一笑,回想當初的自己,不也有此種疑惑麼。。。今天打算針對他的問題,結合一個實際的使用場景來說明下