盡量使用條件屬性(Conditional Attribute)而不是#if/#endif預處理


http://www.cnblogs.com/JiangSoney/archive/2009/08/10/1543197.html


.net框架提供了一個特性:屬性(Attribute),注意:此屬性非彼屬性(property)(這都是翻譯惹的禍)。

.net框架提供了兩種類型的Attribute屬性:內置屬性,自定義屬性。顧名思義,內置屬性是框架已經為我們開發好的在語言中置入的屬性,自定義屬性是用戶自行定義、創建的屬性。其中條件屬性(Conditional Attribute)就是屬於內置屬性。.net框架提供了數百個預先定義好的內置屬性,這就不多說了。下面簡單的說一下怎么創建用戶自定義屬性,從而幫助我們理解什么是Attribute屬性。

首先要搞清楚:設計實現自定義屬性本質就是設計實現一個自定義的類,這個類除了要滿足一般類的要求外還要滿足以下幾個條件:

1、繼承System.Attribute;

2、給該類添加AttributeUsageAttribute屬性,限制屬性類的用法,通過AttributeUsageAttribute類的AttributeTargets參數來指定屬性類可以用於何處。如將屬性類用於類、結構或者方法等等。

舉例說明:

創建一個新的屬性ClassInfo,記錄類的創建時間。 

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class ClassInfoAttribute : Attribute
{
    private string _createDate;

    public ClassInfoAttribute(string createDate)
    {
        _createDate = createDate;
    }

    public string createDate
    {
        get
        {
            return _createDate;
        }
    }
}

 測試類: 

[ClassInfo("2009-08-10")]
public class TClass
{
    public string GetAttribute()
    {
        MemberInfo memInfo = typeof(TClass);
        Object[] attributes = memInfo.GetCustomAttributes(
            typeof(ClassInfoAttribute), false);
        if (0 != attributes.GetLength(0))
        {
            ClassInfoAttribute item = attributes[0] as ClassInfoAttribute;
            if (null != item)
            {
                return item.createDate;
            }
        }
        return string.Empty;
    }

    [Conditional("DEBUG")]
    public virtual void TestAtDebug()
    {
        Console.WriteLine("Test at debuging condition.");
    }

    public void Test()
    {
        Console.WriteLine("Test at normal condition.");
    }
}

 

至此我們應該對Attribute屬性大體了解了。下面來看看條件屬性(Conditional Attribute)到底是怎么回事。

[Conditional("DEBUG")]
public virtual void TestAtDebug()
{
    Console.WriteLine("Test at debuging condition.");
}

public void Test()
{
    Console.WriteLine("Test at normal condition.");
}

 

在debug環境下執行的結果是:

Test at debuging condition.
Test at normal condition.

在release環境下執行的結果是:

Test at normal condition.

 

條件屬性是定義方法的運行環境的。條件屬性只能在方法上使用。使用條件屬性的方法必須符合以下規則:
1、 該方法必須是某個類中的方法;
2、 該方法不能是override方法,但可以是virtual方法。注意:當該方法是virtual方法時,則在派生類中對應的override方法也具有這個屬性;
3、 該方法返回的類型必須是void類型;
4、 該方法不能是接口的實現。
上面講到條件屬性只能在方法上使用,所以你應該用條件屬性來修飾在不同條件下使用的方法,只有當你要在不同條件下使用一塊代碼時才用#if/#endif快修飾,即使這樣你也應該將該段代碼封裝到一個方法中。
再來看個例子:

public class Name
{
    private string _firstName;
    public string FirstName
    {
        set
        {
            CheckName2(value);
            _firstName = value;
        }
    }

    private void CheckName1(string item)
    {
#if DEBUG
        Debug.Assert(!string.IsNullOrEmpty(item), "Name cannot be empty!");
#endif
    }

    [Conditional("DEBUG")]
    private void CheckName2(string item)
    {
        if (string.IsNullOrEmpty(item))
            Console.WriteLine("Name cannot be empty!");
    }

}

 

雖然CheckName1和CheckName2的功能一樣,但是你肯定會更願意選擇CheckName2方法。
下面是Release編譯的程序集被反編譯后的結果:

#if DEBUG/#endif


[Conditional("DEBUG")]


#if DEBUG/#endif只有在debug環境下才會被編譯、執行。當編譯器遇到#if語句后,編譯器會檢查與編譯環境相關的符號是否存在,如果存在,就編譯#if塊中的代碼,如果不存在,編譯器會忽略之后的代碼直到#endif。當采用Conditional屬性時,不管DEBUG環境變量是否被定義,Conditional屬性修飾的方法總會被編譯到程序集中。這或許看上去是低效的,但這只是占用一點硬盤空間,且該方法不會被載入到內存,更不會被編譯成機器代碼,除非它被調用。這樣做的好處是生成更高效的IL(中間語言Intermediate Language)代碼,從而增強程序的可伸縮性,唯一不足的是帶來了一點微不足道的硬盤空間開銷。
另外,如果過多的在程序塊中添加#if/#endif塊,使#if/#endif塊與普通代碼混在一起,容易造成程序結構的混亂,晦澀難懂。並且在調試完之后,為了使用戶不會被這些調試信息弄糊塗,還需要把這些#if/#endif一個一個的去掉,這樣不僅不方便而且容易引發錯誤。#if/#endif的這些缺點正好是Conditional屬性的優點。至於Conditional屬性限制方法的返回類型只能是void類型,不適應返回非void類型的方法,如果你一定要這樣做,別忘了可以給方法傳遞out類型的參數。


總之:Conditional屬性跟#if/#endif預處理比起來,具有以下幾點優勢:
1、可以由定義標記來靈活的控制;
2、可以生成更高效的IL代碼;
3、幫助你強制在條件代碼上使用更好的結構;
4、可以避免因使用#if/#endif而產生的常見的錯誤;
5、能更好的區分條件代碼和普通代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM