Visual Basic之擴充方法(Extension Mothed)

Visual Basic 9 / Visual Basic 2008版本時加入一個擴充方法(Extension Mothed),這個方法可以讓我們很方便就擴充型別的方法,僅僅只有方法哦。在ASP.NET很少用,或是根本沒用到,但想不到,到了ASP.NET MVC,擴充方法的比重大大提升。

在ASP.NET MVC不像ASP.NET裡有很多很多很好用的控制項,所以在ASP.NET MVC中「手工」部份比重增加,所以「重覆」、「客制化」的東西就多,這時有幾種方式來解決
  1. 寫個Function()來處理重覆步驟。
  2. 寫個Class,使用Shared關鍵字來公開方法。
  3. 使用擴充方法,直接擴充相關型別的方法。

寫個Function()來處理重覆步驟

如果Function()程式只會在同一個頁面,或同一個Class中使用,這是很不錯的方法。但如果需要給多個頁面,或多個Class使用,那還不是「重覆中的重覆」,只是一個是複製整段程式碼,一個是複製Function(),有何差別?

寫個Class,使用Shared關鍵字來公開方法

自己寫個Class,使用Shared關鍵字來共用方法,這真好。因為使用了Shared關鍵字,在任何頁面Class中都可以直接引用。

但,你知道整個.NET Framework有多少Class了嗎?記得在一篇文篇裡看過,.NET Framework 2.0就有三萬多個Class,你背得了幾個?再加.NET Framework 4新增的,媽媽咪呀。你覺得不夠用,想要再往上加,你記的起來,別人呢?

使用擴充方法,直接擴充相關型別的方法

使用擴充方法(Extension Method)來擴充相對應型別的方法。一般常用的Class你一定記得起來,例如,String、Integer,當這些Class所提供的方法無法滿足你時,你應該使用擴充方法來擴充即可。

例如,我們想要把使用者輸入的「數字字串」轉換為「中文數字字串」,「1234」轉為「一二三四」,String型別有這個方法嗎?Integer型別有這個方法嗎?沒,所以我們來擴充。

使用擴充方法

  1. 必須寫在「模組」裡,模組必須定義為「Public」
  2. 必須 Imports System.Runtime.CompilerServices
  3. 擴充方法只能是 Function 或 Sub
  4. 擴充方法 Function 或 Sub 前,必須以「擴充屬性 <extension()> 標記
  5. 擴充方法 Function 或 Sub 第一個參考型別表示要擴充的型別

實作擴充方法 for ASP.NET MVC

在ASP.NET與ASP.NET MVC實作擴充方法都一樣,讓我們寫點ASP.NET MVC的東西,所以我們選擇使用ASP.NET MVC來實作。

新增ASP.NET MVC 3專案
如果你使用Visual Basic來撰寫ASP.NET MVC我建議升級至ASP.NET MVC 3版本,最少在「產生程式碼片段」會不出現$end$的錯誤。

' ASP.NET MVC 2 產生程式碼片段
Public Function Action() As ActionResult
Return View()$end$
End Function

' ASP.NET MVC 3 產生程式碼片段
Public Function Action() As ActionResult
    Return View()
End Function

在Controllers資料夾中新增二個「模組」,命名為StringExtension,還有一個LabelExtension(Label這個有個故事)。

StringExtension.vb 模組
Imports System.Runtime.CompilerServices

' 一定Public,不然會出錯
Public Module StringExtension

    ' 第一個參數為String,所以會擴充為String的方法
    ' Visual Basic 2010,有「隱含行接續」,可不行在最後加「底線」
     
    Public Function ToChineseFromNumber(ByVal number As String) As String
        Dim letter As String = Nothing
        Dim Chinese As String = ""
        Dim value As Integer = Nothing

        If (Integer.TryParse(number, value)) Then
            For i As Integer = 0 To number.Length - 1
                letter = number.Substring(i, 1)
                Select Case letter
                    Case "0"
                        Chinese += "零"
                    Case "1"
                        Chinese += "一"
                    Case "2"
                        Chinese += "二"
                    Case "3"
                        Chinese += "三"
                    Case "4"
                        Chinese += "四"
                    Case "5"
                        Chinese += "五"
                    Case "6"
                        Chinese += "六"
                    Case "7"
                        Chinese += "七"
                    Case "8"
                        Chinese += "八"
                    Case "9"
                        Chinese += "九"
                End Select
            Next
        Else
            Chinese = "Must Numbers."
        End If
        Return Chinese
    End Function
End Module

LabelExtension.vb 模組
Imports System.Runtime.CompilerServices

Public Module LabelExtension

    ' 擴充HtmlHelper,即在View中使用Html,擴充後成為Html.LabelFormat()方法
    <extension()>
    Public Function LabelFormat(ByVal helper As HtmlHelper, ByVal target As String, ByVal text As String) As String
        Return String.Format("<label for="{0}">{1}</label>", target, text)
    End Function
End Module

先「建置」專案,然後開啟HomeController.vb,加入擴充方法所在的命名空間「Imports ProjectName.ModuleName」:

HomeController.vb
' 要記得Imports ProjectName.ModuleName
Imports MvcVBExtension.StringExtension

Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Function Index() As ActionResult
        ViewData("Message") = "歡迎使用 ASP.NET MVC!"

        Dim Chinese As String = "1234"
        ' 使用String的擴充方法
        ViewData("Chinese") = Chinese.ToChineseFromNumber()

        Return View()
    End Function

    Function About() As ActionResult
        Return View()
    End Function

End Class

接著我們來看Index.aspx

<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Import Namespace="MvcVBExtension.LabelExtension" %>
<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
    首頁
</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%: ViewData("Message") %></h2>
    <p>
        若要進一步了解 ASP.NET MVC,請造訪 <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>。
    </p>
    <p>
    String擴充方法:<%: ViewData("Chinese")%>
    </p>
    <p>
    Label擴充方法:<%= Html.LabelFormat("KKBruce", "Bruce Blog")%>
    </p>
</asp:Content>

重點在第二行「<%@ Import Namespace="MvcVBExtension.LabelExtension" %>」,先Imports 命名空間,才有辦法使用Html.LabelFormat擴充方法。

.NET Framework進化到現在4.0,除非需求特別,不然需要再寫新Class的機會實在不大,反而是需要擴充的機會大些,而在ASP.NET MVC中擴充Helper輔助類別又是大宗。

LabelExtension的故事呢?

話說,有些人就是學不乖,犯過了寫,而且還寫了「悔過書--JavaScript之無法form.submit()的錯誤」,2010/12月到現在2011/3月,算算應該才滿三個月的時間,又犯一樣的錯,抓去關算了。

什麼錯,就之前寫擴充方法寫的很高興,但奇怪,怎麼有一個擴充方法怎麼樣就是不能用?在<%= Html. 時,就是不會跑出我寫的那個擴充方法,但你直接下<%= LabelFormat就可以使用,不管我如何清除、重建,就是無法成為HtmlHelper的擴充方法。想說是不是見鬼了,也查了我一整個下午,結果是:


看不懂,沒關係,答案是:


還看不懂我也沒辦法了。命名重覆,哈,我的腦袋跟這些人一樣嗎?怎麼老是想出一樣的名稱。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。