Partilhar via


Refatorar em funções puras (LINQ to XML)

Um aspeto importante das transformações funcionais puras é aprender a refatorar o código usando funções puras.

Nota

A nomenclatura comum na programação funcional é que você refatora programas usando funções puras. Em Visual Basic e C++, isso se alinha com o uso de funções nas respetivas linguagens. No entanto, em C#, as funções são chamadas de métodos. Para os propósitos desta discussão, uma função pura é implementada como um método em C#.

Como observado anteriormente nesta seção, uma função pura tem duas características úteis:

  • Não tem efeitos secundários. A função não altera nenhuma variável ou os dados de qualquer tipo fora da função.
  • É consistente. Dado o mesmo conjunto de dados de entrada, ele sempre retornará o mesmo valor de saída.

Uma maneira de fazer a transição para a programação funcional é refatorar o código existente para eliminar efeitos colaterais desnecessários e dependências externas. Desta forma, você pode criar versões de função pura do código existente.

Este artigo discute o que é uma função pura e o que não é. O tutorial Tutorial: Manipular conteúdo em um documento WordprocessingML mostra como manipular um documento WordprocessingML e inclui dois exemplos de como refatorar usando uma função pura.

Os exemplos a seguir contrastam duas funções não puras e uma função pura.

Exemplo: implementar uma função não pura que altera um membro de classe estática

No código a seguir, a HyphenatedConcat função não é uma função pura, porque modifica o membro da aMember classe estática:

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

Este exemplo produz a seguinte saída:

StringOne-StringTwo

Observe que é irrelevante se os dados que estão sendo modificados têm public ou private acessam, ou se são membros, shared membros ou membros de static instância. Uma função pura não altera nenhum dado fora da função.

Exemplo: implementar uma função não pura que altera um parâmetro

Além disso, a seguinte versão desta mesma função não é pura porque modifica o conteúdo do seu parâmetro, 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

Esta versão do programa produz a mesma saída que a primeira versão, porque a HyphenatedConcat função alterou o valor (estado) do seu primeiro parâmetro invocando a Append função membro. Observe que essa alteração ocorre apesar do fato de que HyphenatedConcat usa passagem de parâmetro chamada por valor.

Importante

Para tipos de referência, se você passar um parâmetro por valor, isso resultará em uma cópia da referência a um objeto que está sendo passado. Essa cópia ainda está associada aos mesmos dados de instância que a referência original (até que a variável de referência seja atribuída a um novo objeto). Chamada por referência não é necessariamente necessária para uma função modificar um parâmetro.

Exemplo: Implementar uma função pura

Esta próxima versão do programa mostra como implementar a função como uma função pura 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

Mais uma vez, esta versão produz a mesma linha de saída: StringOne-StringTwo. Observe que, para reter o valor concatenado, ele é armazenado na variável s2intermediária.

Uma abordagem que pode ser muito útil é escrever funções que são localmente impuras (ou seja, declaram e modificam variáveis locais), mas são globalmente puras. Tais funções têm muitas das características de composição desejáveis, mas evitam algumas das expressões de programação funcional mais complicadas, como ter que usar recursão quando um loop simples realizaria a mesma coisa.

Operadores de consulta padrão

Uma característica importante dos operadores de consulta padrão é que eles são implementados como funções puras.

Para obter mais informações, consulte Visão geral dos operadores de consulta padrão (C#) e Visão geral dos operadores de consulta padrão (Visual Basic).

Consulte também