クラスClasses

クラスは、プロパティ、メソッド、およびイベントを持つことができるオブジェクトを表す型です。Classes are types that represent objects that can have properties, methods, and events.

構文Syntax

// Class definition:
type [access-modifier] type-name [type-params] [access-modifier] ( parameter-list ) [ as identifier ] =
[ class ]
[ inherit base-type-name(base-constructor-args) ]
[ let-bindings ]
[ do-bindings ]
member-list
...
[ end ]
// Mutually recursive class definitions:
type [access-modifier] type-name1 ...
and [access-modifier] type-name2 ...
...

RemarksRemarks

クラスは、.NET オブジェクト型の基本的な記述を表します。クラスは、F# オブジェクト指向プログラミングをサポートする型の主な概念です。Classes represent the fundamental description of .NET object types; the class is the primary type concept that supports object-oriented programming in F#.

上記の構文type-nameでは、は任意の有効な識別子です。In the preceding syntax, the type-name is any valid identifier. type-paramsは、省略可能なジェネリック型パラメーターについて説明します。The type-params describes optional generic type parameters. 型パラメーター名と、山かっこ (<>) で囲まれた制約で構成されます。It consists of type parameter names and constraints enclosed in angle brackets (< and >). 詳細については、「ジェネリック制約」を参照してください。For more information, see Generics and Constraints. parameter-list 、コンストラクターのパラメーターについて説明します。The parameter-list describes constructor parameters. 最初のアクセス修飾子は、型に関連します。2つ目は、プライマリコンストラクターに関連します。The first access modifier pertains to the type; the second pertains to the primary constructor. どちらの場合も、既定値publicはです。In both cases, the default is public.

クラスの基底クラスは、 inheritキーワードを使用して指定します。You specify the base class for a class by using the inherit keyword. 基底クラスのコンストラクターには、かっこで囲んだ引数を指定する必要があります。You must supply arguments, in parentheses, for the base class constructor.

letバインドを使用してクラスに対してローカルなフィールドまたは関数値を宣言します。また、letバインドの一般的な規則に従う必要があります。You declare fields or function values that are local to the class by using let bindings, and you must follow the general rules for let bindings. do-bindingsバインド セクションには、オブジェクト構築時に実行されるコードが含まれています。The do-bindings section includes code to be executed upon object construction.

member-list 、追加のコンストラクター、インスタンスと静的メソッドの宣言、インターフェイス宣言、抽象バインディング、およびプロパティとイベント宣言で構成されています。The member-list consists of additional constructors, instance and static method declarations, interface declarations, abstract bindings, and property and event declarations. これらについては、「メンバー」を参照してください。These are described in Members.

省略可能asなキーワードと共に使用されるでは、インスタンス変数または自己識別子に名前が付けられます。これは、型のインスタンスを参照するために型定義で使用できます。identifierThe identifier that is used with the optional as keyword gives a name to the instance variable, or self identifier, which can be used in the type definition to refer to the instance of the type. 詳細については、このトピックで後述する「自己識別子」を参照してください。For more information, see the section Self Identifiers later in this topic.

定義のclass開始endと終了をマークするキーワードとは省略可能です。The keywords class and end that mark the start and end of the definition are optional.

相互に再帰的に参照される型である相互再帰型は、相互andに再帰的な関数と同様に、キーワードと共に結合されます。Mutually recursive types, which are types that reference each other, are joined together with the and keyword just as mutually recursive functions are. 例については、「相互再帰型」を参照してください。For an example, see the section Mutually Recursive Types.

コンストラクターConstructors

コンストラクターは、クラス型のインスタンスを作成するコードです。The constructor is code that creates an instance of the class type. これは、他の .NET 言語で、クラスのコンストラクターは F# のやや異なる方法で機能します。Constructors for classes work somewhat differently in F# than they do in other .NET languages. F#クラスでは、常に、 parameter-list型名の後のに記述される引数を持つプライマリコンストラクターがあります。また、 let本体は、クラス宣言の先頭にある (とlet rec) バインディングと、do次に続くバインディング。In an F# class, there is always a primary constructor whose arguments are described in the parameter-list that follows the type name, and whose body consists of the let (and let rec) bindings at the start of the class declaration and the do bindings that follow. プライマリコンストラクターの引数は、クラス宣言全体でスコープ内にあります。The arguments of the primary constructor are in scope throughout the class declaration.

次のnewように、キーワードを使用してメンバーを追加することにより、追加のコンストラクターを追加できます。You can add additional constructors by using the new keyword to add a member, as follows:

new(argument-list) = constructor-bodynew(argument-list) = constructor-body

新しいコンストラクターの本体は、クラス宣言の先頭に指定されているプライマリコンストラクターを呼び出す必要があります。The body of the new constructor must invoke the primary constructor that is specified at the top of the class declaration.

次の例は、この概念を示しています。The following example illustrates this concept. 次のコードではMyClass 、に2つのコンストラクターがあります。これは、2つの引数を受け取るプライマリコンストラクターと、引数を受け取らない別のコンストラクターです。In the following code, MyClass has two constructors, a primary constructor that takes two arguments and another constructor that takes no arguments.

type MyClass1(x: int, y: int) =
   do printfn "%d %d" x y
   new() = MyClass1(0, 0)

letdoバインドlet and do Bindings

クラスlet定義do内のとのバインドは、プライマリクラスのコンストラクターの本体を形成するため、クラスのインスタンスが作成されるたびに実行されます。The let and do bindings in a class definition form the body of the primary class constructor, and therefore they run whenever a class instance is created. letバインディングが関数の場合は、メンバーにコンパイルされます。If a let binding is a function, then it is compiled into a member. letバインディングが、どの関数またはメンバーでも使用されていない値である場合は、コンストラクターに対してローカルな変数にコンパイルされます。If the let binding is a value that is not used in any function or member, then it is compiled into a variable that is local to the constructor. それ以外の場合は、クラスのフィールドにコンパイルされます。Otherwise, it is compiled into a field of the class. doの式は、プライマリコンストラクターにコンパイルされ、すべてのインスタンスに対して初期化コードを実行します。The do expressions that follow are compiled into the primary constructor and execute initialization code for every instance. 追加のコンストラクターは常にプライマリコンストラクターを呼び出すletため、 doバインドとバインドは、呼び出されるコンストラクターに関係なく、常に実行されます。Because any additional constructors always call the primary constructor, the let bindings and do bindings always execute regardless of which constructor is called.

バインドによってlet作成されたフィールドには、クラスのメソッドとプロパティを通じてアクセスできます。ただし、静的メソッドがパラメーターとしてインスタンス変数を受け取る場合でも、静的メソッドからアクセスすることはできません。Fields that are created by let bindings can be accessed throughout the methods and properties of the class; however, they cannot be accessed from static methods, even if the static methods take an instance variable as a parameter. 自己識別子 (存在する場合) を使用してアクセスすることはできません。They cannot be accessed by using the self identifier, if one exists.

自己識別子Self Identifiers

Self 識別子は、現在のインスタンスを表す名前です。A self identifier is a name that represents the current instance. 自己識別子C#は、 thisまたC++はMe Visual Basic のキーワードに似ています。Self identifiers resemble the this keyword in C# or C++ or Me in Visual Basic. 自己識別子は、クラス定義全体のスコープ内にあるか、または個別のメソッドのスコープ内にあるかに応じて、2つの異なる方法で定義できます。You can define a self identifier in two different ways, depending on whether you want the self identifier to be in scope for the whole class definition or just for an individual method.

クラス全体の自己識別子を定義するには、コンストラクター asのパラメーターリストの終わりかっこの後にキーワードを使用し、識別子の名前を指定します。To define a self identifier for the whole class, use the as keyword after the closing parentheses of the constructor parameter list, and specify the identifier name.

1つのメソッドに対してのみ自己識別子を定義するには、メンバー宣言内の自己識別子を、メソッド名の直前とピリオド (.) の区切り記号として指定します。To define a self identifier for just one method, provide the self identifier in the member declaration, just before the method name and a period (.) as a separator.

次のコード例は、自己識別子を作成する2つの方法を示しています。The following code example illustrates the two ways to create a self identifier. 最初の行asでは、キーワードを使用して自己識別子を定義します。In the first line, the as keyword is used to define the self identifier. 5行目では、識別子thisを使用して、スコープがメソッドPrintMessageに限定された自己識別子を定義します。In the fifth line, the identifier this is used to define a self identifier whose scope is restricted to the method PrintMessage.

type MyClass2(dataIn) as self =
    let data = dataIn
    do
        self.PrintMessage()
    member this.PrintMessage() =
        printf "Creating MyClass2 with Data %d" data

他の .NET 言語とは異なり、自己識別子には名前を付けることができます。、 selfMeなどの名前に制限されてthisいません。Unlike in other .NET languages, you can name the self identifier however you want; you are not restricted to names such as self, Me, or this.

asキーワードを使用して宣言された自己識別子は、 letバインドが実行されるまで初期化されません。The self identifier that is declared with the as keyword is not initialized until after the let bindings are executed. したがって、 letバインドでは使用できません。Therefore, it cannot be used in the let bindings. [ doバインド] セクションでは、自己識別子を使用できます。You can use the self identifier in the do bindings section.

ジェネリック型の型パラメーターGeneric Type Parameters

ジェネリック型パラメーターは、山かっこ (<>) で指定され、単一引用符の後に識別子が続きます。Generic type parameters are specified in angle brackets (< and >), in the form of a single quotation mark followed by an identifier. 複数のジェネリック型パラメーターは、コンマで区切られます。Multiple generic type parameters are separated by commas. ジェネリック型パラメーターは、宣言全体でスコープ内にあります。The generic type parameter is in scope throughout the declaration. ジェネリック型パラメーターを指定する方法を次のコード例に示します。The following code example shows how to specify generic type parameters.

type MyGenericClass<'a> (x: 'a) =
   do printfn "%A" x

型引数は、型が使用されるときに推論されます。Type arguments are inferred when the type is used. 次のコードでは、推論される型は組のシーケンスです。In the following code, the inferred type is a sequence of tuples.

let g1 = MyGenericClass( seq { for i in 1 .. 10 -> (i, i*i) } )

継承の指定Specifying Inheritance

inherit句は、直接基底クラス (存在する場合) を識別します。The inherit clause identifies the direct base class, if there is one. でF#は、直接基底クラスを1つだけ使用できます。In F#, only one direct base class is allowed. クラスが実装するインターフェイスは、基本クラスとは見なされません。Interfaces that a class implements are not considered base classes. インターフェイスについては、「インターフェイス」を参照してください。Interfaces are discussed in the Interfaces topic.

識別子として言語キーワードbaseを使用し、その後にピリオド (.) とメンバーの名前を指定することで、派生クラスから基底クラスのメソッドとプロパティにアクセスできます。You can access the methods and properties of the base class from the derived class by using the language keyword base as an identifier, followed by a period (.) and the name of the member.

詳細については、「継承」を参照してください。For more information, see Inheritance.

Members セクションMembers Section

このセクションでは、静的メソッド、インスタンスメソッド、プロパティ、インターフェイスの実装、抽象メンバー、イベント宣言、および追加のコンストラクターを定義できます。You can define static or instance methods, properties, interface implementations, abstract members, event declarations, and additional constructors in this section. Let と do のバインドは、このセクションには記述できません。Let and do bindings cannot appear in this section. 別のトピックで説明されている、メンバーは、さまざまなクラスのほか、F# の型に追加することができます、ためメンバーします。Because members can be added to a variety of F# types in addition to classes, they are discussed in a separate topic, Members.

相互再帰型Mutually Recursive Types

相互参照する型を循環する方法で定義する場合は、 andキーワードを使用して型定義を文字列で連結します。When you define types that reference each other in a circular way, you string together the type definitions by using the and keyword. キーワードandは、最初typeの定義以外のすべてのキーワードを次のように置き換えます。The and keyword replaces the type keyword on all except the first definition, as follows.

open System.IO

type Folder(pathIn: string) =
  let path = pathIn
  let filenameArray : string array = Directory.GetFiles(path)
  member this.FileArray = Array.map (fun elem -> new File(elem, this)) filenameArray

and File(filename: string, containingFolder: Folder) =
   member this.Name = filename
   member this.ContainingFolder = containingFolder

let folder1 = new Folder(".")
for file in folder1.FileArray do
   printfn "%s" file.Name

出力は、現在のディレクトリにあるすべてのファイルの一覧です。The output is a list of all the files in the current directory.

クラス、共用体、レコード、および構造体を使用する場合When to Use Classes, Unions, Records, and Structures

さまざまな種類から選択できるように、それぞれの型が特定の状況に適した型を選択できるように設計されていることを十分に理解しておく必要があります。Given the variety of types to choose from, you need to have a good understanding of what each type is designed for to select the appropriate type for a particular situation. クラスは、オブジェクト指向プログラミングコンテキストで使用するように設計されています。Classes are designed for use in object-oriented programming contexts. オブジェクト指向プログラミングは、.NET Framework 用に記述されたアプリケーションで使用される最も重要なパラダイムです。Object-oriented programming is the dominant paradigm used in applications that are written for the .NET Framework. F#コードを .NET Framework または別のオブジェクト指向ライブラリと密接に連携させる必要がある場合、特に UI ライブラリなどのオブジェクト指向型システムから拡張する必要がある場合は、クラスが適切である可能性があります。If your F# code has to work closely with the .NET Framework or another object-oriented library, and especially if you have to extend from an object-oriented type system such as a UI library, classes are probably appropriate.

オブジェクト指向のコードと密接に相互運用していない場合、または自己完結型のコードを記述していて、オブジェクト指向のコードと頻繁にやり取りする場合は、レコードと判別共用体の使用を検討する必要があります。If you are not interoperating closely with object-oriented code, or if you are writing code that is self-contained and therefore protected from frequent interaction with object-oriented code, you should consider using records and discriminated unions. 適切なパターン一致コードと共に1つのよく見られる判別共用体が、オブジェクト階層の代替手段として使用されることがよくあります。A single, well thought–out discriminated union, together with appropriate pattern matching code, can often be used as a simpler alternative to an object hierarchy. 判別共用体の詳細については、「判別共用体」を参照してください。For more information about discriminated unions, see Discriminated Unions.

レコードにはクラスよりも単純な利点がありますが、型の要求が単純さで実現できることを超える場合、レコードは適切ではありません。Records have the advantage of being simpler than classes, but records are not appropriate when the demands of a type exceed what can be accomplished with their simplicity. レコードは、基本的には値の単純な集計であり、カスタムアクションを実行できる個別のコンストラクターと、非表示フィールドを除いて、継承やインターフェイスの実装は不要です。Records are basically simple aggregates of values, without separate constructors that can perform custom actions, without hidden fields, and without inheritance or interface implementations. プロパティやメソッドなどのメンバーをレコードに追加して、動作をより複雑にすることができますが、レコードに格納されているフィールドは、引き続き単純な値の集計になります。Although members such as properties and methods can be added to records to make their behavior more complex, the fields stored in a record are still a simple aggregate of values. レコードの詳細については、「レコード」を参照してください。For more information about records, see Records.

構造体は、データの小さな集計にも役立ちますが、クラスとレコードは .NET 値型であるとは異なります。Structures are also useful for small aggregates of data, but they differ from classes and records in that they are .NET value types. クラスとレコードは .NET 参照型です。Classes and records are .NET reference types. 値型と参照型のセマンティクスは、値型が値で渡されるという意味で異なります。The semantics of value types and reference types are different in that value types are passed by value. これは、パラメーターとして渡された場合、または関数から返された場合にビットのビットがコピーされることを意味します。This means that they are copied bit for bit when they are passed as a parameter or returned from a function. また、これらはスタックに格納されます。また、フィールドとして使用されている場合は、ヒープ上の別の場所に格納されるのではなく、親オブジェクト内に埋め込まれます。They are also stored on the stack or, if they are used as a field, embedded inside the parent object instead of stored in their own separate location on the heap. したがって、ヒープにアクセスするオーバーヘッドが問題になる場合は、構造体が頻繁にアクセスされるデータに適しています。Therefore, structures are appropriate for frequently accessed data when the overhead of accessing the heap is a problem. 構造体の詳細については、「構造体」を参照してください。For more information about structures, see Structures.

関連項目See also