Partilhar via


Propriedades (F#)

As propriedades são membros que representam valores associados a um objeto.

Sintaxe

// Property that has both get and set defined.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [accessibility-modifier] get() =
    get-function-body
and [accessibility-modifier] set parameter =
    set-function-body

// Alternative syntax for a property that has get and set.
[ attributes-for-get ]
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName =
    get-function-body
[ attributes-for-set ]
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
with set parameter =
    set-function-body

// Property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName =
    get-function-body

// Alternative syntax for property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with get() =
    get-function-body

// Property that has set only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with set parameter =
    set-function-body

// Automatically implemented properties.
[ attributes ]
[ static ] member val [accessibility-modifier] PropertyName = initialization-expression [ with get, set ]

Observações

As propriedades representam a relação "tem uma" na programação orientada a objetos, representando dados associados a instâncias de objeto ou, para propriedades estáticas, ao tipo.

Você pode declarar propriedades de duas maneiras, dependendo se deseja especificar explicitamente o valor subjacente (também chamado de armazenamento de suporte) para a propriedade ou se deseja permitir que o compilador gere automaticamente o armazenamento de suporte para você. Geralmente, você deve usar a maneira mais explícita se a propriedade tiver uma implementação não trivial e a maneira automática quando a propriedade for apenas um wrapper simples para um valor ou variável. Para declarar uma propriedade explicitamente, use a member palavra-chave. Essa sintaxe declarativa é seguida pela sintaxe que especifica os get métodos e set , também chamados de acessadores. As várias formas da sintaxe explícita mostradas na seção de sintaxe são usadas para propriedades de leitura/gravação, somente leitura e somente gravação. Para propriedades somente leitura, você define apenas um método, para propriedades somente gravação get , define apenas um set método. Observe que quando uma propriedade tem ambos e getset acessadores, a sintaxe alternativa permite especificar atributos e modificadores de acessibilidade que são diferentes para cada acessador, como é mostrado no código a seguir.

// A read-only property.
member this.MyReadOnlyProperty = myInternalValue
// A write-only property.
member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value
// A read-write property.
member this.MyReadWriteProperty
    with get () = myInternalValue
    and set (value) = myInternalValue <- value

Para propriedades de leitura/gravação, que têm um get e set método, a ordem de get e set pode ser invertida. Como alternativa, você pode fornecer a sintaxe mostrada apenas para get e a sintaxe mostrada para set somente em vez de usar a sintaxe combinada. Fazer isso torna mais fácil comentar o indivíduo get ou set método, se isso é algo que você pode precisar fazer. Essa alternativa ao uso da sintaxe combinada é mostrada no código a seguir.

member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value

Os valores privados que contêm os dados das propriedades são chamados de repositórios de backup. Para que o compilador crie o armazenamento de suporte automaticamente, use as palavras-chave member val, omita o autoidentificador e, em seguida, forneça uma expressão para inicializar a propriedade. Se a propriedade for mutável, inclua with get, set. Por exemplo, o seguinte tipo de classe inclui duas propriedades implementadas automaticamente. Property1 é somente leitura e é inicializado para o argumento fornecido ao construtor primário, e Property2 é uma propriedade settable inicializada para uma cadeia de caracteres vazia:

type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set

As propriedades implementadas automaticamente fazem parte da inicialização de um tipo, portanto, elas devem ser incluídas antes de qualquer outra definição de membro, assim como let associações e do associações em uma definição de tipo. Observe que a expressão que inicializa uma propriedade implementada automaticamente só é avaliada após a inicialização, e não toda vez que a propriedade é acessada. Esse comportamento contrasta com o comportamento de uma propriedade explicitamente implementada. O que isso efetivamente significa é que o código para inicializar essas propriedades é adicionado ao construtor de uma classe. Considere o seguinte código que mostra essa diferença:

type MyClass() =
    let random  = new System.Random()
    member val AutoProperty = random.Next() with get, set
    member this.ExplicitProperty = random.Next()

let class1 = new MyClass()

printfn $"class1.AutoProperty = %d{class1.AutoProperty}"
printfn $"class1.ExplicitProperty = %d{class1.ExplicitProperty}"

Saída

class1.AutoProperty = 1853799794
class1.AutoProperty = 1853799794
class1.ExplicitProperty = 978922705
class1.ExplicitProperty = 1131210765

A saída do código anterior mostra que o valor de AutoProperty é inalterado quando chamado repetidamente, enquanto o ExplicitProperty muda cada vez que é chamado. Isso demonstra que a expressão para uma propriedade implementada automaticamente não é avaliada cada vez, assim como o método getter para a propriedade explícita.

Aviso

Existem algumas bibliotecas, como o Entity Framework (System.Data.Entity) que executam operações personalizadas em construtores de classe base que não funcionam bem com a inicialização de propriedades implementadas automaticamente. Nesses casos, tente usar propriedades explícitas.

As propriedades podem ser membros de classes, estruturas, uniões discriminadas, registros, interfaces e extensões de tipo e também podem ser definidas em expressões de objeto.

Os atributos podem ser aplicados às propriedades. Para aplicar um atributo a uma propriedade, escreva o atributo em uma linha separada antes da propriedade. Para obter mais informações, consulte Atributos.

Por padrão, as propriedades são públicas. Os modificadores de acessibilidade também podem ser aplicados às propriedades. Para aplicar um modificador de acessibilidade, adicione-o imediatamente antes do nome da propriedade, se for para se aplicar aos get métodos e set e adicione-o antes das get palavras-chave e set se for necessária uma acessibilidade diferente para cada acessador. O modificador de acessibilidade pode ser um dos seguintes: public, private, internal. Para obter mais informações, consulte Controle de acesso.

As implementações de propriedade são executadas cada vez que uma propriedade é acessada.

Propriedades estáticas e de instância

As propriedades podem ser estáticas ou de instância. As propriedades estáticas podem ser invocadas sem uma instância e são usadas para valores associados ao tipo, não a objetos individuais. Para propriedades estáticas, omita o autoidentificador. O autoidentificador é necessário para propriedades de exemplo.

A definição de propriedade estática a seguir é baseada em um cenário no qual você tem um campo myStaticValue estático que é o armazenamento de suporte para a propriedade.

static member MyStaticProperty
    with get() = myStaticValue
    and set(value) = myStaticValue <- value

As propriedades também podem ser semelhantes a matrizes, caso em que são chamadas de propriedades indexadas. Para obter mais informações, consulte Propriedades indexadas.

Anotação de tipo para propriedades

Em muitos casos, o compilador tem informações suficientes para inferir o tipo de uma propriedade a partir do tipo do armazenamento de suporte, mas você pode definir o tipo explicitamente adicionando uma anotação de tipo.

// To apply a type annotation to a property that does not have an explicit
// get or set, apply the type annotation directly to the property.
member this.MyProperty1 : int = myInternalValue
// If there is a get or set, apply the type annotation to the get or set method.
member this.MyProperty2 with get() : int = myInternalValue

Usando acessadores de conjunto de propriedades

Você pode definir propriedades que fornecem set acessadores usando o <- operador .

// Assume that the constructor argument sets the initial value of the
// internal backing store.
let mutable myObject = new MyType(10)
myObject.MyProperty <- 20
printfn "%d" (myObject.MyProperty)

A saída é 20.

Propriedades abstratas

As propriedades podem ser abstratas. Tal como acontece com os métodos, abstract apenas significa que há um despacho virtual associado à propriedade. As propriedades abstratas podem ser verdadeiramente abstratas, isto é, sem uma definição na mesma classe. A classe que contém tal propriedade é, portanto, uma classe abstrata. Alternativamente, abstrato pode significar apenas que uma propriedade é virtual e, nesse caso, uma definição deve estar presente na mesma classe. Observe que as propriedades abstratas não devem ser privadas, e se um acessador é abstrato, o outro também deve ser abstrato. Para obter mais informações sobre classes abstratas, consulte Classes abstratas.

// Abstract property in abstract class.
// The property is an int type that has a get and
// set method
[<AbstractClass>]
type AbstractBase() =
    abstract Property1: int with get, set

// Implementation of the abstract property
type Derived1() =
    inherit AbstractBase()
    let mutable value = 10

    override this.Property1
        with get () = value
        and set (v: int) = value <- v

// A type with a "virtual" property.
type Base1() =
    let mutable value = 10
    abstract Property1: int with get, set

    default this.Property1
        with get () = value
        and set (v: int) = value <- v

// A derived type that overrides the virtual property
type Derived2() =
    inherit Base1()
    let mutable value2 = 11

    override this.Property1
        with get () = value2
        and set (v) = value2 <- v

Consulte também