Compartilhar via


Propriedades (F#)

As propriedades são membros que representam os 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 ]

Comentários

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

Você pode declarar as propriedades de duas maneiras, dependendo de se você deseja especificar explicitamente o valor subjacente (também chamado de repositório de suporte) para a propriedade ou se deseja permitir que o compilador gere automaticamente o repositório de backup 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 uma variável. Para declarar uma propriedade explicitamente, use a palavra-chave member. Essa sintaxe declarativa é seguida pela sintaxe que especifica os métodos get 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 leitura/gravação, somente leitura e somente gravação. Para propriedades somente leitura, defina apenas um método get. Para propriedades somente gravação, defina apenas um método set. Observe que, quando uma propriedade tem ambos os acessadores get e set, a sintaxe alternativa permite que você especifique atributos e modificadores de acessibilidade diferentes para cada acessador, conforme 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 ambos os métodos get e set, a ordem de get e de set pode ser invertida. Como alternativa, você pode fornecer somente a sintaxe mostrada para get e somente a sintaxe mostrada para set, vez de usar a sintaxe combinada. Fazer isso facilita os comentários sobre o get individual ou o método set, caso necessário. Essa alternativa de usar a 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 repositório de backup automaticamente, use as palavras-chave member val, omita o autoidentificador e forneça uma expressão para inicializar a propriedade. Se a propriedade for mutável, inclua with get, set. Por exemplo, o tipo de classe a seguir inclui duas propriedades implementadas automaticamente. Property1 é somente leitura e é inicializada para o argumento fornecido ao construtor primário e Property2 é uma propriedade configurável 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, devem ser incluídas antes de qualquer outra definição de membro, assim como as associações let e as associações do em uma definição de tipo. Observe que a expressão que inicializa uma propriedade implementada automaticamente é avaliada somente após a inicialização e não toda vez que a propriedade é acessada. Esse comportamento é diferente do comportamento de uma propriedade implementada explicitamente. Efetivamente, isso 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 não é alterado quando chamado repetidamente, enquanto que ExplicitProperty é alterado sempre que é chamado. Isso demonstra que a expressão de uma propriedade implementada automaticamente não é avaliada toda vez, assim como o método getter para a propriedade explícita.

Aviso

Há algumas bibliotecas, como o Entity Framework (System.Data.Entity), que executam operações personalizadas nos construtores de classe base que não funcionam corretamente 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 nas expressões de objeto.

Os atributos podem ser aplicados a propriedades. Para aplicar um atributo a uma propriedade, grave 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 a propriedades. Para aplicar um modificador de acessibilidade, adicione-o imediatamente antes do nome da propriedade, caso seja destinado a se aplicar aos métodos get e set, e adicione-o antes das palavras-chave get e set caso uma acessibilidade diferente seja necessária para cada acessador. O modificador de acessibilidade pode ser um dos seguintes: public, private, internal. Para mais informações, consulte Controle de acesso.

As implementações de propriedade são executadas sempre 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, e não com objetos individuais. Para propriedades estáticas, omita o autoidentificador. O autoidentificador é necessário para propriedades de instância.

A definição de propriedade estática a seguir é baseada em um cenário no qual você tem um campo estático myStaticValue, que é o repositório de backup da propriedade.

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

As propriedades também podem ser semelhantes à matriz. Nesse caso, são chamadas de propriedades indexadas. Para obter mais informações, confira Propriedades Indexadas.

Anotação de Tipo para Propriedades

Em muitos casos, o compilador tem informações suficientes para inferir o tipo de uma propriedade do tipo do repositório de backup, 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

Uso de acessadores definidos pela propriedade

Você pode definir propriedades que forneçam os acessadores set 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. Assim como acontece com os métodos, abstract significa apenas que existe uma expedição virtual associada à propriedade. As propriedades abstratas podem ser verdadeiramente abstratas, ou seja, sem uma definição na mesma classe. A classe que contém essa propriedade é, portanto, uma classe abstrata. Como alternativa, o termo abstrato pode significar apenas que uma propriedade é virtual e, nesse caso, uma definição deve ser encontrada na mesma classe. Observe que as propriedades abstratas não devem ser privadas e, se um acessador for abstrato, o outro também deverá ser abstrato. Para obter mais informações sobre classes abstratas, confira 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

Confira também