重構為純函式 (LINQ to XML)

純功能性轉換的重要觀點為學習如何使用純虛擬函式重構程式碼。

注意

功能性程式設計的常見命名法為使用純虛擬函式重構程式。 在 Visual Basic 和 C++ 中,這可以利用個別的語言,調整函式的用法。 不過,在 C# 中,函式稱為方法。 就這個討論而言,純虛擬函式會當成 C# 中的方法實作。

如同本節先前所述,純虛擬函式擁有兩個實用的特性:

  • 它有沒有副作用。 函式不會變更函式以外任何類型的任何變數或資料。
  • 其有一致性。 假設是相同的輸入資料集合,就永遠會傳回相同的輸出值。

轉換為功能性程式設計的其中一種方式為重構現有的程式碼以排除不必要的副作用與外部相依性。 以此種方式,您可以建立現有程式碼的純虛擬函式版本。

本文會討論什麼是純函式,以及什麼不是純函式。 教學課程:操作 WordprocessingML 文件中的內容教學課程顯示如何操作 WordprocessingML 文件,並包含兩個如何使用純函式重構的範例。

下列範例對照兩個非純虛擬函式與一個純虛擬函式。

範例:實作變更靜態類別成員的非純函式

在下列程式碼中,HyphenatedConcat 函式不是純函式,因為其會修改 aMember 靜態類別成員:

public class Program
{
    private static string aMember = "StringOne";

    public static void HyphenatedConcat(string appendStr)
    {
        aMember += '-' + appendStr;
    }

    public static void Main()
    {
        HyphenatedConcat("StringTwo");
        Console.WriteLine(aMember);
    }
}
Module Module1
    Dim aMember As String = "StringOne"

    Public Sub HyphenatedConcat(ByVal appendStr As String)
        aMember = aMember & "-" & appendStr
    End Sub

    Sub Main()
        HyphenatedConcat("StringTwo")
        Console.WriteLine(aMember)
    End Sub
End Module

這個範例會產生下列輸出:

StringOne-StringTwo

請注意,不管要修改的資料具有 publicprivate 存取權,或者是 static 成員及 shared 成員,亦或是執行個體成員,都沒有關係。 純函式不會變更函式以外的任何資料。

範例:實作變更參數的非純函式

此外,此相同函式的下列版本不是純函式,因為其會修改其參數 sb 的內容。

public class Program
{
    public static void HyphenatedConcat(StringBuilder sb, String appendStr)
    {
        sb.Append('-' + appendStr);
    }

    public static void Main()
    {
        StringBuilder sb1 = new StringBuilder("StringOne");
        HyphenatedConcat(sb1, "StringTwo");
        Console.WriteLine(sb1);
    }
}
Module Module1
    Public Sub HyphenatedConcat(ByVal sb As StringBuilder, ByVal appendStr As String)
        sb.Append("-" & appendStr)
    End Sub

    Sub Main()
        Dim sb1 As StringBuilder = New StringBuilder("StringOne")
        HyphenatedConcat(sb1, "StringTwo")
        Console.WriteLine(sb1)
    End Sub
End Module

這個版本的程式會產生與第一版相同的輸出,因為 HyphenatedConcat 函式已經叫用 Append 成員函式來變更其第一個參數的值 (狀態)。 請注意,雖然 HyphenatedConcat 使用 call-by-value 參數傳遞,但還是會發生此變更。

重要

若是參考型別 (Reference Type),如果您依據值傳遞參數,會使參考的副本傳遞到物件。 這個副本仍然跟原始參考一樣,與相同的執行個體資料相關聯 (直到將參考變數指派給新的物件)。 對於要修改參數的函式,則不一定需要 Call-by-reference。

範例:實作純函式

這個下一版的程式會顯示如何將 HyphenatedConcat 函式實作為純虛擬函式。

class Program
{
    public static string HyphenatedConcat(string s, string appendStr)
    {
        return (s + '-' + appendStr);
    }

    public static void Main(string[] args)
    {
        string s1 = "StringOne";
        string s2 = HyphenatedConcat(s1, "StringTwo");
        Console.WriteLine(s2);
    }
}
Module Module1
    Public Function HyphenatedConcat(ByVal s As String, ByVal appendStr As String) As String
        Return (s & "-" & appendStr)
    End Function

    Sub Main()
        Dim s1 As String = "StringOne"
        Dim s2 As String = HyphenatedConcat(s1, "StringTwo")
        Console.WriteLine(s2)
    End Sub
End Module

再次聲明,這個版本會產生相同的輸出行:StringOne-StringTwo。 請注意,若要保留串連值,則其會儲存於中繼變數 s2 中。

其中一個可能非常實用的方法是,撰寫在本機非純虛擬但全域為純虛擬的函式 (亦即,它們可以宣告並修改本機變數)。 這類函式擁有許多值得撰寫的特性,但是會避免某些更錯綜複雜的功能性程式設計慣用句,例如,當簡易迴圈可以完成相同的事情時,必須使用遞迴。

標準查詢運算子

標準查詢運算子的重要特性為其會以純函式實作。

如需詳細資訊,請參閱標準查詢運算子概觀 (C#)標準查詢運算子概觀 (Visual Basic)

另請參閱