在類別庫專案中將列舉型別定義在命名空間

七月是個令人歡欣鼓舞的月份,許多朋友這幾天都接到微軟通知獲選或是連任MVP的通知,雖然在噗浪已經狂賀一輪了,在這邊還是要恭喜他們,很開心他們的努力有獲得微軟的認可。言歸正傳,因為這幾天在改以前寫的類別庫,突然讓我想起為何 .Net中的列舉都是在命名空間﹝Namespace﹞中,而我的都寫在類別裡面;是不是自訂類別庫不能將列舉放在命名空間中呢?

       七月是個令人歡欣鼓舞的月份,許多朋友這幾天都接到微軟通知獲選或是連任MVP的通知,雖然在噗浪已經狂賀一輪了,在這邊還是要恭喜他們,很開心他們的努力有獲得微軟的認可。言歸正傳,因為這幾天在改以前寫的類別庫,突然讓我想起為何 .Net中的列舉都是在命名空間﹝Namespace﹞中,而我的都寫在類別裡面;是不是自訂類別庫不能將列舉放在命名空間中呢?後來在MSDN Library中看到這麼一句話「通常最好是在命名空間內直接定義 enum,讓該命名空間中的所有類別都能同樣便利地存取它。不過,enum 也可以透過巢狀方式置於個類別或結構 (Struct) 中。」﹝原文引述自 MSDN文件庫  [C# 語言參考 enum (C# 參考)]﹞。

       一般我們寫類別庫專案會這麼做,選擇類別庫範本,然後給它個名稱,於是開發環境就會自動跑出預設的一個類別程式檔Class1.vb﹝在C#中則為Class1.cs﹞;當我們要寫一個新的類別時通常會用【類別範本】來加入一個新的類別程式碼。通常是像以下這樣寫:

Public Class Class1

    Public Enum Poker
        Spade = 3
        Heart = 2
        Diamond = 1
        Club = 0
    End Enum

    Public Function Test00() As Poker
        Return Poker.Club
    End Function

End Class

      這樣造成了一麻煩是不論我是在這個專案的另一個類別程式碼或是在應用程式型態的程式碼中要使用 Poker這個列舉都必需加上Class1字樣,像以下的情形雖然程式寫起來正常,但總覺得看起來很醜:

Public Class Class2
    Public Function Test0() As Class1.Poker
        Return Class1.Poker.Club
    End Function
End Class

或是

Imports CSTest3
Public Class Form3
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        TextBox1.Text = Class1.Poker.Heart
    End Sub
End Class

      於是乎我又開始神遊MSDN文件庫,在 [Namespace 陳述式]中找到一線希望﹝以下原文引述自 MSDN文件庫﹞: 

 

  • 根命名空間:專案中的所有命名空間名稱都是依據「根命名空間」而命名。Visual Studio 會根據專案內的所有程式碼,將專案名稱指定為預設根命名空間的名稱。例如,如果專案已命名為 Payroll,則它的程式設計項目會屬於命名空間 Payroll。如果宣告 Namespace funding,則該命名空間的完整名稱是 Payroll.funding。

    如果想要在 Namespace 陳述式中指定現有的命名空間 (例如在泛型清單類別範例中),可以將根命名空間設定成 null 值。若要執行這項作業,請按一下 [專案] 功能表中的 [專案屬性],再清除 [根命名空間] 項目,讓方塊空白。如果在泛型清單類別範例中不這樣做,則 Visual Basic 編譯器會將 System.Collections.Generic 當做專案 Payroll 內的新命名空間,而這個命名空間的完整名稱則為 Payroll.System.Collections.Generic。

    或者可以使用 Global 關鍵字,以參考在專案外部定義的命名空間項目。這樣做可以讓您保留專案名稱做為根命名空間的名稱。這會減少意外合併程式設計項目與現NS01有命名空間之程式設計項目的機會。

          

     

     

     

           太開心了,原來只要這麼簡單的動作就可以了,那就來開始試試吧。一樣先建立一個類別庫專案名稱為CSTest,然後打開方案的屬性視窗,把「根命名空間」的文字清空。

          這時候只要用【程式碼檔範本】開一個新的檔案 CodeFile1.vb,將會得到空白一片,然後加入以下程式碼:

    Namespace NSTest
        Public Enum ESwitch
            _Off = 0
            _On = 1
        End Enum
        Public Class CSEnumTest01

            Public Function Test00() As ESwitch
                Dim i As Integer
                i = ESwitch._On
                Return i
            End Function
            Public Function Text01() As Poker
                Dim i As Integer
                i = Poker.Club
                Return i
            End Function
        End Class
    End Namespace

        再開一個 CodeFile2.vb,加入以下程式碼:

    Namespace NSTest
        Public Enum Poker
            Spade = 0
            Heart = 1
            Diamond = 2
            Club = 3
        End Enum
        Public Class CSEnumTest02
            Public Function Test00() As Poker
                Return Poker.Diamond
            End Function
            Public Function Test01() As ESwitch
                Return ESwitch._Off
            End Function
        End Class
    End Namespace

            這樣的寫法使得ESwitch列舉和 Poker列舉都成為全域的,也就是說當我們引用這個列舉時已經不需要再加上類別名稱,如以下的例子,而且此時Imports的命名空間並不是方案名稱CSTest而是程式碼中的NSTest

     Imports NSTest

    Public Class Form1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            TextBox1.Text = Poker.Diamond
        End Sub
    End Class

           附帶一提的是後來想說再測測看,又發現了另外一種寫法,一樣用傳統的方法建立類別庫專案,一樣用【類別範本】,只要像以下這樣把列舉放在類別外寫,列舉也會變成全域的:

    Public Enum Poker
        Spade = 3
        Heart = 2
        Diamond = 1
        Club = 0
    End Enum
    Public Class Class1
        Public Function Test00() As Poker
            Return Poker.Club
        End Function
    End Class

           璉大另外提示了一個解法,就是在VB.NET中也可以把列舉放入模組檔裡,因為模組本身就是全域性的。最後希望這篇文章能夠讓大家對命名空間有多一點的認識,如果各位有任何其它的做法,也煩請不吝指教。

          《後記1》感謝台北聽友蹂躪提供的新方法:發現其實只要用【程式碼檔範本】開一個新的檔案 CodeFile1.vb,將會得到空白一片,然後加入相關列舉的程式碼就行了:

    Public Enum Enum0
        x = 0
        y = 1
    End Enum
    Public Enum Enum1
        No = 0
        Yes = 1
    End Enum

  • 《後記2》關於之前講到使用根命名空間空白的地方,我少說了一件事,就是那種作法可以讓我們在一個DLL中產生兩個以上不同的命名空間。