Partilhar 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 ]

Observações

Na sintaxe anterior, você pode ver as várias formas de declarações de método e definições. 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 para 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 obter informações sobre inlineo , consulte Funções embutidas.

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

Métodos de instância

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

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

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 identificador automático para acessar campos definidos usando associações de permissão. Use o identificador automático 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 palavra-chave let , 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 SomeType método estão na 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 despacho virtual e pode não ter uma definição na classe. Um slot de despacho virtual é uma entrada em uma tabela de funções mantida internamente que é usada em tempo de execução para procurar chamadas de função virtual em um tipo orientado a objeto. O mecanismo de despacho 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, consulte Classes abstratas.

As declarações de método abstrato não incluem um corpo de 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 Códigos do Visual Studio, exceto sem nomes de parâmetro. As assinaturas de tipo também são exibidas pelo intérprete, fsi.exe, quando você está trabalhando interativamente. A assinatura de tipo de um método é formada listando os tipos dos parâmetros, seguido pelo tipo de retorno, com símbolos separadores apropriados. Os parâmetros curried são separados por -> e os parâmetros de tupla são separados por *. O valor de retorno é 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 em vez de dois parâmetros.

Você também pode dar 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 do .NET Framework. Independentemente de existir ou não uma definição, a abstract palavra-chave cria um novo slot de despacho 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 use a override palavra-chave ou default e forneça 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 do .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#, argumentos opcionais geralmente são usados em vez de métodos sobrecarregados. No entanto, métodos sobrecarregados são permitidos na língua, desde que os argumentos estejam na forma de tupla, não na forma enrolada.

Argumentos opcionais

A partir de 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 para DefaultParameterValue deve corresponder ao tipo de entrada. Na amostra acima, é um intarquivo . Tentar passar um valor não inteiro para DefaultParameterValue dentro 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

Consulte também