プロパティ (F#)

"Properties" は、オブジェクトに関連付けられる値を表すメンバーです。

構文

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

解説

プロパティは、オブジェクト指向プログラミングにおける "has a" リレーションシップを表し、オブジェクト インスタンスまたは型 (静的プロパティの場合) に関連付けられるデータを表します。

プロパティは、プロパティの基になる値 (バッキング ストアとも呼ばれます) を明示的に指定するか、またはコンパイラがバッキング ストアを自動的に生成できるようにするかどうかに応じて、2 つの方法で宣言することができます。 通常、プロパティが自明ではない実装を持つ場合はより明示的な方法を使用し、プロパティが値または変数の単純なラッパーにすぎない場合は自動的な方法を使用する必要があります。 プロパティを明示的に宣言するには、member キーワードを使用します。 この宣言型の構文の後に、get および set メソッド ("アクセサー" とも呼ばれます) を指定する構文が続きます。 構文のセクションで示す明示的な構文のさまざまな形式は、読み取り/書き込み、読み取り専用、書き込み専用のプロパティに使用されます。 読み取り専用プロパティの場合は get メソッドのみを定義し、書き込み専用プロパティの場合は set メソッドのみを定義します。 プロパティに getset の両方のアクセサーがある場合、次のコードに示すように、代替の構文を使用することにより、各アクセサーに対して異なる属性とアクセシビリティ修飾子を指定できることにご注意ください。

// 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

getset の両方のメソッドがある読み取り/書き込みプロパティの場合、getset の順序を逆にすることができます。 また、組み合わせた構文を使用する代わりに、get にのみ表示される構文と set にのみ表示される構文を指定することもできます。 こうすることにより、個々の get または set メソッドにコメント アウトする必要がある場合、簡単に行うことができます。 組み合わせ構文の代わりに使用するこの構文を次のコードに示します。

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

プロパティのデータを保持するプライベート値は、"バッキング ストア" と呼ばれます。 バッキング ストアをコンパイラに自動的に作成させるには、キーワード member val を使用し、自己識別子を省略して、プロパティを初期化する式を指定します。 プロパティが変更不能である場合、with get, set を含めます。 たとえば、次のクラス型には、自動的に実装される 2 つのプロパティが含まれます。 Property1 は、読み取り専用で、プライマリ コンストラクターに指定された引数に初期化され、Property2 は、設定可能なプロパティで、空の文字列に初期化されます。

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

自動的に実装されるプロパティは、型の初期化の一部であるため、型定義の let バインディングや do バインディングと同様に、他のメンバー定義の前に含める必要があります。 自動的に実装されるプロパティを初期化する式が評価されるのは、初期化時のみであり、プロパティにアクセスするたびではないことにご注意ください。 この動作は、明示的に実装されるプロパティの動作とは対照的です。 事実上、これは、これらのプロパティを初期化するコードがクラスのコンストラクターに追加されることを意味します。 この違いを示す次のコードについて考えてみましょう。

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}"

出力

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

前述のコードの出力は、AutoProperty の値が繰り返し呼び出された場合に変更されないことを示します。一方、ExplicitProperty は、呼び出されるたびに変更されます。 これは、自動的に実装されるプロパティの式は、明示的なプロパティの getter メソッドと同様に、毎回評価されないことを示しています。

警告

Entity Framework (System.Data.Entity) など、自動的に実装されるプロパティの初期化ではうまく機能しない基底クラス コンストラクターでカスタム操作を実行するライブラリがいくつかあります。 このような場合、明示的なプロパティを使用してみてください。

プロパティは、クラス、構造体、判別された共用体、レコード、インターフェイス、型拡張のメンバーにすることができ、オブジェクト式で定義することもできます。

プロパティに属性を適用することができます。 プロパティに属性を適用するには、プロパティの前に別の行で属性を記述します。 詳細については、「属性」を参照してください。

既定では、プロパティはパブリックです。 プロパティにアクセシビリティ修飾子を適用することもできます。 アクセシビリティ修飾子を適用するには、getsetの両方のメソッドに適用する場合は、アクセシビリティ修飾子をプロパティ名の直前に追加します。アクセサーごとに異なるアクセシビリティが必要な場合は、get および set キーワードの前に追加します。 accessibility-modifier は、publicprivateinternal のいずれかにすることができます。 詳しくは、「アクセス制御」をご覧ください。

プロパティの実装は、プロパティにアクセスするたびに実行されます。

静的プロパティとインスタンス プロパティ

プロパティは、静的プロパティまたはインスタンス プロパティのいずれかになります。 静的プロパティは、インスタンスなしで呼び出すことができ、個々のオブジェクトではなく型に関連付けられる値に使用されます。 静的プロパティの場合は、自己識別子を省略します。 インスタンス プロパティには、自己識別子が必要です。

次の静的プロパティの定義は、プロパティのバッキング ストアである静的フィールド myStaticValue があるシナリオに基づいています。

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

プロパティを配列のようにすることもできます。その場合、"インデックス付きプロパティ" と呼ばれます。 詳細については、「インデックス付きプロパティ」を参照してください。

プロパティの型の注釈

多くの場合、コンパイラにはバッキング ストアの型からプロパティの型を推測するのに十分な情報がありますが、型の注釈を追加することで型を明示的に設定できます。

// 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

プロパティ セット アクセサーの使用

<- 演算子を使用して set アクセサーを提供するプロパティを設定できます。

// 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)

出力は、20になります。

抽象プロパティ

プロパティを抽象化することができます。 メソッドと同様、abstract は、プロパティに関連付けられた仮想ディスパッチがあることを意味します。 抽象プロパティは、完全に抽象化できます。つまり、同じクラスに定義を指定する必要はありません。 したがって、このようなプロパティを含むクラスは、抽象クラスです。 また、抽象は、プロパティが仮想であることを意味する場合があり、その場合、定義は同じクラスに存在する必要があります。 抽象プロパティをプライベートにすることはできません。また、一方のアクセサーが抽象である場合、もう一方も抽象でなければならないことにご注意ください。 抽象クラスの詳細については、「抽象クラス」を参照してください。

// 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

関連項目