Compartilhar via


Métodos

Um método é uma função associada a um tipo. Na programação orientada a objetos, os métodos são usados para expor e implementar a funcionalidade e o comportamento de objetos e tipos.

Sintaxe

// Instance method definition.
[ attributes ]
member [inline] self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Static method definition.
[ attributes ]
static member [inline] method-name parameter-list [ : return-type ] =
    method-body

// Abstract method declaration or virtual dispatch slot.
[ attributes ]
abstract member method-name : type-signature

// Virtual method declaration and default implementation.
[ attributes ]
abstract member method-name : type-signature
[ attributes ]
default self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Override of inherited virtual method.
[ attributes ]
override self-identifier.method-name parameter-list [ : return-type ] =
    method-body

// Optional and DefaultParameterValue attributes on input parameters
[ attributes ]
[ modifier ] member [inline] self-identifier.method-name ([<Optional; DefaultParameterValue( default-value )>] input) [ : return-type ]

Comentários

Na sintaxe anterior, você pode ver as várias formas de declarações e definições de método. Em corpos de método mais longos, uma quebra de linha segue o sinal de igual (=) e todo o corpo do método é recuado.

Os atributos podem ser aplicados a qualquer declaração de método. Eles precedem a sintaxe de uma definição de método e geralmente são listados em uma linha separada. Para obter mais informações, consulte Atributos.

Os métodos podem ser marcados inline. Para saber mais sobre inline, veja Funções embutidas.

Métodos não embutidos podem ser usados recursivamente dentro do tipo; não é necessário usar explicitamente a rec palavra-chave.

Métodos de instância

Os métodos de instância são declarados com a memberpalavra-chave e um auto-identificador, seguidos por um período (.) e o nome e os parâmetros do método. Como é o caso let das associações, a lista de parâmetros pode ser um padrão. Normalmente, você inclui parâmetros de método em parênteses em um formulário de tupla, que é a maneira como os métodos aparecem em F# quando eles são criados em outras linguagens .NET Framework. No entanto, a forma curried (parâmetros separados por espaços) também é comum, e outros padrões também têm suporte.

O exemplo a seguir ilustra a definição e o uso de um método de instância não abstrato.

type SomeType(factor0: int) =
    let factor = factor0
    member this.SomeMethod(a, b, c) = (a + b + c) * factor

    member this.SomeOtherMethod(a, b, c) = this.SomeMethod(a, b, c) * factor

Dentro dos métodos de instância, não use o auto-identificador para acessar campos definidos usando associações de let. Use o auto-identificador ao acessar outros membros e propriedades.

Métodos estáticos

A palavra-chave static é usada para especificar que um método pode ser chamado sem uma instância e não está associado a uma instância de objeto. Caso contrário, os métodos são métodos de instância.

O exemplo na próxima seção mostra campos declarados com a let palavra-chave, os membros da propriedade declarados com a member palavra-chave e um método estático declarado com a static palavra-chave.

O exemplo a seguir ilustra a definição e o uso de métodos estáticos. Suponha que essas definições de método estejam na SomeType classe na seção anterior.

static member SomeStaticMethod(a, b, c) =
   (a + b + c)

static member SomeOtherStaticMethod(a, b, c) =
   SomeType.SomeStaticMethod(a, b, c) * 100

Métodos abstratos e virtuais

A palavra-chave abstract indica que um método tem um slot de expedição virtual e pode não ter uma definição na classe. Um slot de expedição virtual é uma entrada em uma tabela de funções mantida internamente que é usada em tempo de execução para pesquisar chamadas de função virtual em um tipo orientado a objeto. O mecanismo de expedição virtual é o mecanismo que implementa o polimorfismo, uma característica importante da programação orientada a objetos. Uma classe que tem pelo menos um método abstrato sem uma definição é uma classe abstrata, o que significa que nenhuma instância pode ser criada dessa classe. Para obter mais informações sobre classes abstratas, confira Classes Abstratas.

As declarações de método abstrato não incluem um corpo do método. Em vez disso, o nome do método é seguido por dois-pontos (:) e uma assinatura de tipo para o método. A assinatura de tipo de um método é a mesma mostrada pelo IntelliSense quando você pausa o ponteiro do mouse sobre um nome de método no Editor de Visual Studio Code, exceto sem nomes de parâmetro. As assinaturas de tipo também são exibidas pelo interpretador, fsi.exe, quando você está trabalhando interativamente. A assinatura de tipo de um método é formada listando os tipos dos parâmetros, seguidos pelo tipo de retorno, com símbolos separadores apropriados. Os parâmetros curried são separados e -> os parâmetros de tupla são separados por *. O valor retornado é sempre separado dos argumentos por um -> símbolo. Parênteses podem ser usados para agrupar parâmetros complexos, como quando um tipo de função é um parâmetro ou para indicar quando uma tupla é tratada como um único parâmetro e não como dois parâmetros.

Você também pode fornecer definições padrão de métodos abstratos adicionando a definição à classe e usando a default palavra-chave, conforme mostrado no bloco de sintaxe neste tópico. Um método abstrato que tem uma definição na mesma classe é equivalente a um método virtual em outras linguagens .NET Framework. Se existe ou não uma definição, a abstract palavra-chave cria um novo slot de expedição na tabela de funções virtuais para a classe.

Independentemente de uma classe base implementar seus métodos abstratos, as classes derivadas podem fornecer implementações de métodos abstratos. Para implementar um método abstrato em uma classe derivada, defina um método que tenha o mesmo nome e assinatura na classe derivada, exceto usar a override palavra-chave ou default fornecer o corpo do método. As palavras-chave override e default significam exatamente a mesma coisa. Use override se o novo método substituir uma implementação de classe base; use default quando você criar uma implementação na mesma classe que a declaração abstrata original. Não use a abstract palavra-chave no método que implementa o método que foi declarado abstrato na classe base.

O exemplo a seguir ilustra um método Rotate abstrato que tem uma implementação padrão, o equivalente a um método virtual .NET Framework.

type Ellipse(a0: float, b0: float, theta0: float) =
    let mutable axis1 = a0
    let mutable axis2 = b0
    let mutable rotAngle = theta0
    abstract member Rotate: float -> unit
    default this.Rotate(delta: float) = rotAngle <- rotAngle + delta

O exemplo a seguir ilustra uma classe derivada que substitui um método de classe base. Nesse caso, a substituição altera o comportamento para que o método não faça nada.

type Circle(radius: float) =
    inherit Ellipse(radius, radius, 0.0)
    // Circles are invariant to rotation, so do nothing.
    override this.Rotate(_) = ()

Métodos sobrecarregados

Métodos sobrecarregados são métodos que têm nomes idênticos em um determinado tipo, mas que têm argumentos diferentes. Em F#, os argumentos opcionais geralmente são usados em vez de métodos sobrecarregados. No entanto, métodos sobrecarregados são permitidos na linguagem, desde que os argumentos estejam na forma de tupla, não na forma curried.

Argumentos opcionais

A partir do F# 4.1, você também pode ter argumentos opcionais com um valor de parâmetro padrão em métodos. Isso é para ajudar a facilitar a interoperação com o código C#. O exemplo a seguir demonstra a sintaxe:

open System.Runtime.InteropServices
// A class with a method M, which takes in an optional integer argument.
type C() =
    member _.M([<Optional; DefaultParameterValue(12)>] i) = i + 1

Observe que o valor passado deve DefaultParameterValue corresponder ao tipo de entrada. No exemplo acima, é um int. Tentar passar um valor DefaultParameterValue não inteiro resultaria em um erro de compilação.

Exemplo: propriedades e métodos

O exemplo a seguir contém um tipo que tem exemplos de campos, funções privadas, propriedades e um método estático.

type RectangleXY(x1: float, y1: float, x2: float, y2: float) =
    // Field definitions.
    let height = y2 - y1
    let width = x2 - x1
    let area = height * width
    // Private functions.
    static let maxFloat (x: float) (y: float) = if x >= y then x else y
    static let minFloat (x: float) (y: float) = if x <= y then x else y
    // Properties.
    // Here, "this" is used as the self identifier,
    // but it can be any identifier.
    member this.X1 = x1
    member this.Y1 = y1
    member this.X2 = x2
    member this.Y2 = y2
    // A static method.
    static member intersection(rect1: RectangleXY, rect2: RectangleXY) =
        let x1 = maxFloat rect1.X1 rect2.X1
        let y1 = maxFloat rect1.Y1 rect2.Y1
        let x2 = minFloat rect1.X2 rect2.X2
        let y2 = minFloat rect1.Y2 rect2.Y2

        let result: RectangleXY option =
            if (x2 > x1 && y2 > y1) then
                Some(RectangleXY(x1, y1, x2, y2))
            else
                None

        result

// Test code.
let testIntersection =
    let r1 = RectangleXY(10.0, 10.0, 20.0, 20.0)
    let r2 = RectangleXY(15.0, 15.0, 25.0, 25.0)
    let r3: RectangleXY option = RectangleXY.intersection (r1, r2)

    match r3 with
    | Some(r3) -> printfn "Intersection rectangle: %f %f %f %f" r3.X1 r3.Y1 r3.X2 r3.Y2
    | None -> printfn "No intersection found."

testIntersection

Confira também