程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> CLR筆記:17.自定義屬性

CLR筆記:17.自定義屬性

編輯:關於.NET

自定義屬性,使用聲明式編程的方式,HTML也是屬於這種編程方式。

17.1 使用自定義屬性

只是將一些附加信息與某個目標元素關聯起來。編譯器在托管模塊的元數據中生成額外的信息。

從System.Attribute派生,所有符合CLS的屬性都是從這個基類派生。

有定位參數和命名參數兩種,前者必須指定。

可以將多個屬性應用於單個目標元素,用逗號分割。

17.2    定義自己的屬性

屬性類標准寫法:     [AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)]

    public class FlagAttribute : System.Attribute

    {

        public FlagAttribute() { }

    }

注意:1.屬性就是類的一個實例,因此屬性類至少要有一個公共構造器。如果class沒有ctor,就生成 默認ctor,所以也可以編譯通過。

2.這個類不要提供任何公共方法/事件

3.FlagAttribute使用的時候,可以簡寫為[Flag]

4.AttributeTarget枚舉,限定屬性的應用范圍,上面程序說明Flag只能用於Enum類型; AttributeTarget.All表示適用於所有類型。

5.AllowMultiple指出是否可以將屬性多次應用於單個目標:

大部分屬性只能使用一次,如以下代碼會編譯出錯,因為沒有任何意義:

    [Flag]

    [Flag]

    public enum Color

    { 

        Red

    }

少數屬性有必要將屬性多次應用於單個目標,如Conditional屬性類(見17.7)

6.Inherited指出屬性是否能由派生類和重寫成員繼承,如下代碼:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = 

true)]

    internal class TastyAttribute : System.Attribute

    {

        public TastyAttribute() { }

    }


    [Tasty][Serializable]

    internal class BaseType

    {

        [Tasty]

        protected virtual void DoSomething() { }

    }


    internal class DeriveType : BaseType

    {

        protected override void DoSomething() { }

    }

這裡,因為繼承的關系,DerivedType及其方法都有屬性[Tasty]。由於Serializable屬性被標記為不 可繼承,所以DerivedType不可以序列化。

只有class/method/properties/field/event/方法返回值/方法參數,是可繼承的,inherited設為 true。

Inherited屬性不會為派生類生成額外的元數據,不影響派生類行為,只是在程序集中生成額外的元數 據。

補充:從AttributeUsage類的FCL源碼,可以看出:

不設置AttributeUsage屬性,默認為    [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]

17.3    屬性的ctor/Field/Property的數據類型,不能是靜態的

必須限制在盡量小的類型范圍內。

盡量應該避免使用,因為會在ctor中傳遞數組參數,不兼容於CLS(非0基數組不符合CLS)

在屬性中定義Type類型,要使用typeof()方法傳遞參數;定義Object類型,可以傳遞Int32/String等 常量表達式(包括null)如果常量表達式為值類型,則執行時需要裝箱。

    public enum Color { Red }


    class SomeAttribute : Attribute

    {

        public SomeAttribute(String name, Object o, Type[] type) { }

    }


    [Some("Jeff", Color.Red, new Type[]{typeof(Math), typeof(Console)})]

    class SomeType { }

17.4 檢測自定義屬性的使用

在枚舉中,介紹了Format靜態方法,功能基本同ToString()方法,但允許value傳遞一個數值,而不僅 僅是一個Enum類型

           Enum.Format(typeof(Color), 3, "G");

這個方法的實現如下:

        public static String Format(Type enumType, Object value, String format)

        { 

            //檢查枚舉類型是否應用了Flag屬性類型的一個實例

            //false表示不從其派生類中繼續查找

            if(enumType.IsDefined(typeof(FlagsAttribute), false))

            {

                //如果是,將value作為一個位標志處理

            }

            else

            {

                //如果不是,將value作為一個普通枚舉類型

            }

        }

以上使用了Type的IsDefined方法,檢查一個類型上的屬性。

以下介紹檢查一個目標的屬性:如Assembly,module,方法,有3個方法可以使用:

1.IsDefined方法,只是檢查,不構造屬性類的實例,效率很高

Attribute.IsDefine一般有兩個參數,第一個是要檢查的目標.GetType(),第二個是typeof(屬性)。 當目標是Attribute/Type/MemthodInfo時,要使用第三個參數,決定是否要從派生類查找。

2.GetCustomAttributes方法,返回一個應用於目標的屬性數組

        public static void ShowAttribute(MemberInfo attributeTarget)

        {

            Attribute[] attributes = Attribute.GetCustomAttributes

(attributeTarget);


            foreach (Attribute attribute in attributes)

            { 

                //遍歷屬性數組

            }

        }

3.GetCustomAttribute方法,返回應用於目標的制定屬性類的一個實例,使用方法見下一節。

17.5 兩個屬性實例的相互匹配

自定義屬性,要重寫Match()方法,才可以比較兩個屬性實例,否則,會調用System.Attribute的 match()方法,而後者,只是調用Mquals方法。

實例展示了Match的重寫,以及上一節GetCustomAttribute方法的使用

    [Accounts(Accounts.Savings)]

    class ChildAccount { }


    [Accounts(Accounts.Savings | Accounts.Checking)]

    class AdultAccount { }


    class Program

    {

        static void Main(string[] args)

        {

            CanWriteCheck(new ChildAccount());

            CanWriteCheck(new AdultAccount());

        }


        private static void CanWriteCheck(Object obj)

        {

            Attribute checking = new AccountsAttribute(Accounts.Checking);
            //以下語句展示了Attribute的GetCustomAttribute方法

            Attribute validAccount = Attribute.GetCustomAttribute(obj.GetType(), 

typeof(AccountsAttribute), false);


            if ((validAccount != null) && checking.Match(validAccount))

            {

                //obj有寫的權限

            }

        }

    }

[Flags]

    enum Accounts

    {

        Savings = 0x001,

        Checking = 0x002,

    }
    [AttributeUsage(AttributeTargets.Class)]

    public class AccountsAttribute : Attribute

    {

        private Accounts m_accounts;
        public AccountsAttribute(Accounts accounts)

        {
            m_accounts = accounts;

        }
        public override bool Match(object obj)

        {

            //如果基類實現了Match,而基類又不是System.Attribute,就取消下面這段注

釋

            //if (!base.Match(obj))

            //{

            //    return false;

            //}
            //如果基類實現Match,則下面這條語句可以刪除

            //因為this肯定不為null,如果obj為null,則肯定不匹配

            if (obj == null)

            {

                return false;

            }

            //如果基類實現Match,則下面這條語句可以刪除

            //對象屬於不同類型,肯定不匹配

            if (this.GetType() != obj.GetType())

            {

                return false;

            }

            //轉型一定成功,因為由上條語句,對象肯定具有相同的類型

            AccountsClass other = (AccountsClass)obj;

            //以下語句要分別比較各個字段,其中有一個不對就返回false,舉一個例子:

            if ((other.m_accounts & m_accounts) != m_accounts)

            {

                return false;

            }

            return true;
        }
    }

17.6 查找自定義屬性,同時不創建屬性類(即不執行屬性類的代碼)

使用System.Reflection.CustomAttributeData類,使用其靜態方法GetCustomAttributes(),獲取一 個與目標關聯的屬性。4個重載版本,分別接受Assembly/Module/ParameterInfo/MemberInfo參數。

同時要配合使用Assembly.ReflectionOnlyLoad()方法,得到程序集,然後再使用 GetCustomAttributes()方法進行分析

CustomAttributeData類的3個只讀屬性:

1.Constructor,返回ctor形式:Void .ctor(String.String)    //這裡表示ctor有一個String參 數

2.ConstructorArguments,泛型,要傳遞給ctor的參數

3.NamedArguments,泛型,返回要設置的字段,不在ctor中設置的

        public static void ShowAttribute(MemberInfo attributeTarget)

        {

            IList<CustomAttributeData> attributes = 

CustomAttributeData.GetCustomAttributes(attributeTarget);


            foreach (CustomAttributeData attribute in attributes)

            { 

                //遍歷屬性數組

            }

        }

    }

17.7 條件屬性類:使用了System.Diagnostics.ConditionalAttribute的屬性類

#define VERIFY

using System.Diagnostics;


[Conditional("TEST")]

[Conditional("VERIFY")]

class CondAttribute : Attribute { }

[Cond]

public class Program

{
    static void Main()

    {

        Console.WriteLine(Attribute.IsDefined(typeof(Program), typeof

(CondAttribute)));

    }

}

這裡,#define VREIFY語句要定義在using之前,這條語句的有無,決定了CondAttribute是否會在IL 中生成。

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