クラスClasses

クラスは、データメンバー (定数とフィールド)、関数メンバー (メソッド、プロパティ、イベント、インデクサー、演算子、インスタンスコンストラクター、デストラクターと静的コンストラクター)、および入れ子にされた型を含むことができるデータ構造です。A class is a data structure that may contain data members (constants and fields), function members (methods, properties, events, indexers, operators, instance constructors, destructors and static constructors), and nested types. クラス型は、派生クラスが基底クラスを拡張および特殊化できる機構である継承をサポートしています。Class types support inheritance, a mechanism whereby a derived class can extend and specialize a base class.

クラス宣言Class declarations

Class_declarationは、新しいクラスを宣言するtype_declaration (型宣言) です。A class_declaration is a type_declaration (Type declarations) that declares a new class.

class_declaration
    : attributes? class_modifier* 'partial'? 'class' identifier type_parameter_list?
      class_base? type_parameter_constraints_clause* class_body ';'?
    ;

Class_declarationは、省略可能な属性のセット (属性)、オプションの一連のclass_modifiers (クラス修飾子)、オプションの partial 修飾子、その後に省略可能な type_parameter_list (型パラメーター)、オプションの class_base の指定 (クラスの基本仕様) 、省略可能なの仕様 (クラスの基本仕様) の順で構成さ class れます。省略可能なtype_parameter_constraints_clauses (型パラメーター制約) のセットで、その後にclass_body (クラス本体) が続きます。その後にセミコロンが続きます。A class_declaration consists of an optional set of attributes (Attributes), followed by an optional set of class_modifiers (Class modifiers), followed by an optional partial modifier, followed by the keyword class and an identifier that names the class, followed by an optional type_parameter_list (Type parameters), followed by an optional class_base specification (Class base specification) , followed by an optional set of type_parameter_constraints_clauses (Type parameter constraints), followed by a class_body (Class body), optionally followed by a semicolon.

クラス宣言は、 type_parameter_listを提供する場合を除き、 type_parameter_constraints_clauses を指定することはできません。A class declaration cannot supply type_parameter_constraints_clauses unless it also supplies a type_parameter_list.

Type_parameter_listを提供するクラス宣言は、ジェネリッククラス宣言です。A class declaration that supplies a type_parameter_list is a generic class declaration. また、ジェネリッククラスの宣言またはジェネリック構造体の宣言内で入れ子になっているクラスは、それ自体がジェネリッククラスの宣言です。これは、包含する型の型パラメーターを指定して構築された型を作成する必要があるためです。Additionally, any class nested inside a generic class declaration or a generic struct declaration is itself a generic class declaration, since type parameters for the containing type must be supplied to create a constructed type.

クラス修飾子Class modifiers

Class_declarationには、必要に応じてクラス修飾子のシーケンスを含めることができます。A class_declaration may optionally include a sequence of class modifiers:

class_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'abstract'
    | 'sealed'
    | 'static'
    | class_modifier_unsafe
    ;

同じ修飾子がクラス宣言に複数回出現する場合、コンパイル時エラーになります。It is a compile-time error for the same modifier to appear multiple times in a class declaration.

new 修飾子は、入れ子になったクラスで許可されています。The new modifier is permitted on nested classes. このメソッドは、新しい修飾子で説明されているように、クラスが同じ名前で継承されたメンバーを非表示にすることを指定します。It specifies that the class hides an inherited member by the same name, as described in The new modifier. 入れ子になったクラス宣言ではないクラス宣言に new 修飾子が表示される場合、コンパイル時エラーになります。It is a compile-time error for the new modifier to appear on a class declaration that is not a nested class declaration.

publicprotectedinternal、および private 修飾子は、クラスのアクセシビリティを制御します。The public, protected, internal, and private modifiers control the accessibility of the class. クラス宣言が発生したコンテキストによっては、これらの修飾子の一部が許可されない場合があります (アクセシビリティは宣言されています)。Depending on the context in which the class declaration occurs, some of these modifiers may not be permitted (Declared accessibility).

abstractsealed、および static 修飾子については、次のセクションで説明します。The abstract, sealed and static modifiers are discussed in the following sections.

抽象クラスAbstract classes

abstract 修飾子は、クラスが不完全であること、および基底クラスとしてのみ使用されることを示すために使用されます。The abstract modifier is used to indicate that a class is incomplete and that it is intended to be used only as a base class. 抽象クラスは、次のように、非抽象クラスとは異なります。An abstract class differs from a non-abstract class in the following ways:

  • 抽象クラスを直接インスタンス化することはできません。抽象クラスで new 演算子を使用する場合、コンパイル時エラーになります。An abstract class cannot be instantiated directly, and it is a compile-time error to use the new operator on an abstract class. コンパイル時の型が抽象である変数と値を持つことはできますが、このような変数と値は必ずしも null であるか、抽象型から派生した非抽象クラスのインスタンスへの参照を含んでいる必要があります。While it is possible to have variables and values whose compile-time types are abstract, such variables and values will necessarily either be null or contain references to instances of non-abstract classes derived from the abstract types.
  • 抽象クラスは、抽象メンバーを含むことができます (必須ではありません)。An abstract class is permitted (but not required) to contain abstract members.
  • 抽象クラスをシールドにすることはできません。An abstract class cannot be sealed.

非抽象クラスが抽象クラスから派生した場合、非抽象クラスには、継承されたすべての抽象メンバーの実際の実装が含まれている必要があります。これにより、抽象メンバーはオーバーライドされます。When a non-abstract class is derived from an abstract class, the non-abstract class must include actual implementations of all inherited abstract members, thereby overriding those abstract members. この例では、In the example

abstract class A
{
    public abstract void F();
}

abstract class B: A
{
    public void G() {}
}

class C: B
{
    public override void F() {
        // actual implementation of F
    }
}

抽象クラス A には、F抽象メソッドが導入されています。the abstract class A introduces an abstract method F. クラス B には、追加のメソッド Gが導入されていますが、Fの実装が提供されていないため、B も abstract として宣言する必要があります。Class B introduces an additional method G, but since it doesn't provide an implementation of F, B must also be declared abstract. クラス CF をオーバーライドし、実際の実装を提供します。Class C overrides F and provides an actual implementation. Cには抽象メンバーがないため、C は非抽象にすることができます (必須ではありません)。Since there are no abstract members in C, C is permitted (but not required) to be non-abstract.

シールクラスSealed classes

sealed 修飾子は、クラスからの派生を防ぐために使用されます。The sealed modifier is used to prevent derivation from a class. シールクラスが別のクラスの基底クラスとして指定されている場合、コンパイル時エラーが発生します。A compile-time error occurs if a sealed class is specified as the base class of another class.

シールクラスを抽象クラスにすることもできません。A sealed class cannot also be an abstract class.

sealed 修飾子は、意図しない派生を防ぐために主に使用されますが、特定の実行時の最適化を有効にすることもできます。The sealed modifier is primarily used to prevent unintended derivation, but it also enables certain run-time optimizations. 特に、シールクラスは派生クラスを持たないことがわかっているため、シールされたクラスインスタンスでの仮想関数メンバー呼び出しを非仮想呼び出しに変換することができます。In particular, because a sealed class is known to never have any derived classes, it is possible to transform virtual function member invocations on sealed class instances into non-virtual invocations.

静的クラスStatic classes

static 修飾子は、クラスが静的クラスとして宣言されていることを示すために使用されます。The static modifier is used to mark the class being declared as a static class. 静的クラスはインスタンス化できません。型として使用することはできず、静的メンバーのみを含めることができます。A static class cannot be instantiated, cannot be used as a type and can contain only static members. 拡張メソッド (拡張メソッド) の宣言を含めることができるのは、静的クラスだけです。Only a static class can contain declarations of extension methods (Extension methods).

静的クラスの宣言には、次の制限があります。A static class declaration is subject to the following restrictions:

  • 静的クラスには、sealed または abstract 修飾子を含めることはできません。A static class may not include a sealed or abstract modifier. ただし、静的クラスはインスタンス化することも、から派生することもできないため、シールドと抽象の両方として動作します。Note, however, that since a static class cannot be instantiated or derived from, it behaves as if it was both sealed and abstract.
  • 静的クラスにclass_base仕様 (クラスの基本仕様) を含めることはできません。また、基底クラスまたは実装されたインターフェイスのリストを明示的に指定することもできません。A static class may not include a class_base specification (Class base specification) and cannot explicitly specify a base class or a list of implemented interfaces. 静的クラスは、型 objectから暗黙的に継承します。A static class implicitly inherits from type object.
  • 静的クラスには、静的メンバー (静的メンバーとインスタンスメンバー) のみを含めることができます。A static class can only contain static members (Static and instance members). 定数および入れ子にされた型は、静的メンバーとして分類されることに注意してください。Note that constants and nested types are classified as static members.
  • 静的クラスには、protected または protected internal によって宣言されたアクセシビリティを持つメンバーを含めることはできません。A static class cannot have members with protected or protected internal declared accessibility.

これらの制限に違反すると、コンパイル時にエラーが発生します。It is a compile-time error to violate any of these restrictions.

静的クラスには、インスタンスコンストラクターがありません。A static class has no instance constructors. 静的クラスでインスタンスコンストラクターを宣言することはできません。また、静的クラスに既定のインスタンスコンストラクター (既定のコンストラクター) は用意されていません。It is not possible to declare an instance constructor in a static class, and no default instance constructor (Default constructors) is provided for a static class.

静的クラスのメンバーは自動的に静的ではなく、メンバー宣言には static 修飾子を明示的に含める必要があります (定数と入れ子にされた型を除く)。The members of a static class are not automatically static, and the member declarations must explicitly include a static modifier (except for constants and nested types). クラスが静的外部クラス内で入れ子になっている場合、入れ子になったクラスは、明示的に static 修飾子を含んでいない限り、静的クラスにはなりません。When a class is nested within a static outer class, the nested class is not a static class unless it explicitly includes a static modifier.

静的クラス型の参照Referencing static class types

では、 namespace_or_type_name (名前空間と型名) に静的クラスを参照することが許可されています。A namespace_or_type_name (Namespace and type names) is permitted to reference a static class if

  • Namespace_or_type_nameT.Iフォームのnamespace_or_type_nameT です。The namespace_or_type_name is the T in a namespace_or_type_name of the form T.I, or
  • Namespace_or_type_nameは、typeof(T)フォームのtypeof_expression (引数リスト1) の T です。The namespace_or_type_name is the T in a typeof_expression (Argument lists1) of the form typeof(T).

Primary_expression (関数メンバー) は、静的クラスを参照することが許可されています。A primary_expression (Function members) is permitted to reference a static class if

それ以外のコンテキストでは、静的クラスを参照するコンパイル時エラーになります。In any other context it is a compile-time error to reference a static class. たとえば、静的クラスを基底クラス、構成型 (入れ子にされた)、ジェネリック型引数、または型パラメーター制約として使用すると、エラーになります。For example, it is an error for a static class to be used as a base class, a constituent type (Nested types) of a member, a generic type argument, or a type parameter constraint. 同様に、静的クラスは、配列型、ポインター型、new 式、キャスト式、is 式、as 式、sizeof 式、または既定値式では使用できません。Likewise, a static class cannot be used in an array type, a pointer type, a new expression, a cast expression, an is expression, an as expression, a sizeof expression, or a default value expression.

Partial 修飾子Partial modifier

このclass_declarationが部分型の宣言であることを示すには、partial 修飾子を使用します。The partial modifier is used to indicate that this class_declaration is a partial type declaration. 外側の名前空間または型宣言内で同じ名前を持つ複数の部分型宣言を組み合わせると、部分型で指定された規則に従って1つの型宣言が形成されます。Multiple partial type declarations with the same name within an enclosing namespace or type declaration combine to form one type declaration, following the rules specified in Partial types.

クラスの宣言をプログラムテキストの個別のセグメントに分散させると、これらのセグメントが異なるコンテキストで生成または管理される場合に便利です。Having the declaration of a class distributed over separate segments of program text can be useful if these segments are produced or maintained in different contexts. たとえば、クラス宣言の一部はコンピューターによって生成される場合がありますが、もう一方の部分は手動で作成されます。For instance, one part of a class declaration may be machine generated, whereas the other is manually authored. 2つのテキストを分離することで、1つの更新がもう一方の更新と競合するのを防ぐことができます。Textual separation of the two prevents updates by one from conflicting with updates by the other.

型パラメーターType parameters

型パラメーターは、構築された型を作成するために提供される型引数のプレースホルダーを示す単純な識別子です。A type parameter is a simple identifier that denotes a placeholder for a type argument supplied to create a constructed type. 型パラメーターは、後で提供される型の正式なプレースホルダーです。A type parameter is a formal placeholder for a type that will be supplied later. これに対して、型引数 (型引数) は、構築された型が作成されるときに、型パラメーターの代わりに使用される実際の型です。By contrast, a type argument (Type arguments) is the actual type that is substituted for the type parameter when a constructed type is created.

type_parameter_list
    : '<' type_parameters '>'
    ;

type_parameters
    : attributes? type_parameter
    | type_parameters ',' attributes? type_parameter
    ;

type_parameter
    : identifier
    ;

クラス宣言の各型パラメーターは、そのクラスの宣言空間 (宣言) に名前を定義します。Each type parameter in a class declaration defines a name in the declaration space (Declarations) of that class. そのため、別の型パラメーターまたはそのクラスで宣言されたメンバーと同じ名前を持つことはできません。Thus, it cannot have the same name as another type parameter or a member declared in that class. 型パラメーターには、型自体と同じ名前を指定することはできません。A type parameter cannot have the same name as the type itself.

クラスの基本指定Class base specification

クラス宣言にはclass_baseの仕様を含めることができます。この仕様では、クラスの直接的な基本クラスと、クラスによって直接実装されたインターフェイス (インターフェイス) が定義されています。A class declaration may include a class_base specification, which defines the direct base class of the class and the interfaces (Interfaces) directly implemented by the class.

class_base
    : ':' class_type
    | ':' interface_type_list
    | ':' class_type ',' interface_type_list
    ;

interface_type_list
    : interface_type (',' interface_type)*
    ;

クラス宣言で指定される基底クラスは、構築されたクラス型 (構築型) にすることができます。The base class specified in a class declaration can be a constructed class type (Constructed types). 基底クラスは、独自の型パラメーターにすることはできませんが、スコープ内の型パラメーターを含めることができます。A base class cannot be a type parameter on its own, though it can involve the type parameters that are in scope.

class Extend<V>: V {}            // Error, type parameter used as base class

基底クラスBase classes

Class_baseclass_typeが含まれている場合は、宣言されているクラスの直接基底クラスを指定します。When a class_type is included in the class_base, it specifies the direct base class of the class being declared. クラス宣言にclass_baseがない場合、またはclass_baseがインターフェイス型のみを一覧表示する場合は、直接基底クラスが objectと見なされます。If a class declaration has no class_base, or if the class_base lists only interface types, the direct base class is assumed to be object. クラスは、「継承」で説明されているように、直接基底クラスからメンバーを継承します。A class inherits members from its direct base class, as described in Inheritance.

この例では、In the example

class A {}

class B: A {}

クラス ABの直接基底クラスと呼ばれ、BAから派生したものと呼ばれます。class A is said to be the direct base class of B, and B is said to be derived from A. A は直接基底クラスを明示的に指定していないため、その直接の基底クラスは暗黙的に objectます。Since A does not explicitly specify a direct base class, its direct base class is implicitly object.

構築されたクラス型の場合、基底クラスがジェネリッククラス宣言で指定されている場合、基本クラスの宣言の各type_parameterに対して、構築された型の基底クラスが、構築された型の対応するtype_argumentとして取得されます。For a constructed class type, if a base class is specified in the generic class declaration, the base class of the constructed type is obtained by substituting, for each type_parameter in the base class declaration, the corresponding type_argument of the constructed type. 指定されたジェネリッククラス宣言Given the generic class declarations

class B<U,V> {...}

class G<T>: B<string,T[]> {...}

構築された型 G<int> の基本クラスは B<string,int[]>ます。the base class of the constructed type G<int> would be B<string,int[]>.

クラス型の直接基底クラスは、少なくともクラス型自体 (アクセシビリティドメイン) と同じようにアクセス可能である必要があります。The direct base class of a class type must be at least as accessible as the class type itself (Accessibility domains). たとえば、public クラスが private または internal クラスから派生する場合、コンパイル時エラーになります。For example, it is a compile-time error for a public class to derive from a private or internal class.

クラス型の直接基底クラスは、System.ArraySystem.DelegateSystem.MulticastDelegateSystem.Enum、または System.ValueTypeのいずれの型でもない必要があります。The direct base class of a class type must not be any of the following types: System.Array, System.Delegate, System.MulticastDelegate, System.Enum, or System.ValueType. さらに、ジェネリッククラスの宣言では、System.Attribute を直接または間接的な基底クラスとして使用することはできません。Furthermore, a generic class declaration cannot use System.Attribute as a direct or indirect base class.

クラス Bの直接的な基底クラスの指定 A の意味を判断する際、B の直接の基底クラスは一時的に objectと見なされます。While determining the meaning of the direct base class specification A of a class B, the direct base class of B is temporarily assumed to be object. 直感的に言えば、基底クラスの指定の意味は、それ自体に再帰的に依存することはできません。Intuitively this ensures that the meaning of a base class specification cannot recursively depend on itself. 次に例を示します。The example:

class A<T> {
   public class B {}
}

class C : A<C.B> {}

は、基底クラスの仕様では、C の直接基底クラスが objectと見なされ、そのため (名前空間と型名の規則によって) C にメンバー Bがあるとは見なされない A<C.B>、エラーになります。is in error since in the base class specification A<C.B> the direct base class of C is considered to be object, and hence (by the rules of Namespace and type names) C is not considered to have a member B.

クラス型の基底クラスは、直接基底クラスとその基本クラスです。The base classes of a class type are the direct base class and its base classes. つまり、基本クラスのセットは、直接基底クラスのリレーションシップの推移的なクロージャです。In other words, the set of base classes is the transitive closure of the direct base class relationship. 上の例を参照して、B の基本クラスは A および objectです。Referring to the example above, the base classes of B are A and object. この例では、In the example

class A {...}

class B<T>: A {...}

class C<T>: B<IComparable<T>> {...}

class D<T>: C<T[]> {...}

D<int> の基本クラスは、C<int[]>B<IComparable<int[]>>A、および objectです。the base classes of D<int> are C<int[]>, B<IComparable<int[]>>, A, and object.

クラス objectを除き、すべてのクラス型には、直接基底クラスが1つだけあります。Except for class object, every class type has exactly one direct base class. object クラスには、直接の基底クラスはなく、他のすべてのクラスの最終的な基本クラスです。The object class has no direct base class and is the ultimate base class of all other classes.

クラス B クラス Aから派生した場合、ABに依存していると、コンパイル時にエラーになります。When a class B derives from a class A, it is a compile-time error for A to depend on B. クラスは、直接基底クラス (存在する場合)に依存し、そのクラスがすぐに入れ子になっているクラスに直接依存します (存在する場合)。A class directly depends on its direct base class (if any) and directly depends on the class within which it is immediately nested (if any). この定義により、クラスが依存するクラスの完全なセットは、リレーションシップに直接依存しているの再帰的および推移的なクロージャです。Given this definition, the complete set of classes upon which a class depends is the reflexive and transitive closure of the directly depends on relationship.

The example

class A: A {}

は、クラスがそれ自体に依存しているため、エラーになります。is erroneous because the class depends on itself. 同様に、例を次に示します。Likewise, the example

class A: B {}
class B: C {}
class C: A {}

クラスが循環的に依存しているため、エラーが発生しています。is in error because the classes circularly depend on themselves. 最後に、例を示します。Finally, the example

class A: B.C {}

class B: A
{
    public class C {}
}

AB.C (直接のクラス) に依存しているため、コンパイル時エラーが発生します。これは、循環的に Aに依存している B (すぐ外側のクラス) に依存します。results in a compile-time error because A depends on B.C (its direct base class), which depends on B (its immediately enclosing class), which circularly depends on A.

クラスは、その中に入れ子になっているクラスに依存しないことに注意してください。Note that a class does not depend on the classes that are nested within it. この例では、In the example

class A
{
    class B: A {}
}

BA に依存します (A は直接の基底クラスであり、そのすぐ外側のクラスでもあるため)。ただし、AB に依存しません (B は基本クラスでも外側のクラスでもありません)。AB depends on A (because A is both its direct base class and its immediately enclosing class), but A does not depend on B (since B is neither a base class nor an enclosing class of A). したがって、この例は有効です。Thus, the example is valid.

sealed クラスから派生させることはできません。It is not possible to derive from a sealed class. この例では、In the example

sealed class A {}

class B: A {}            // Error, cannot derive from a sealed class

クラス B は、sealed クラス Aからの派生を試行しているため、エラーになっています。class B is in error because it attempts to derive from the sealed class A.

インターフェイスの実装Interface implementations

Class_baseの指定には、インターフェイス型のリストを含めることができます。この場合、クラスは、指定されたインターフェイス型を直接実装すると言います。A class_base specification may include a list of interface types, in which case the class is said to directly implement the given interface types. インターフェイスの実装については、「インターフェイスの実装」で詳しく説明します。Interface implementations are discussed further in Interface implementations.

型パラメーターの制約Type parameter constraints

ジェネリック型およびメソッドの宣言では、 type_parameter_constraints_clauses を含めることにより、必要に応じて型パラメーターの制約を指定できます。Generic type and method declarations can optionally specify type parameter constraints by including type_parameter_constraints_clauses.

type_parameter_constraints_clause
    : 'where' type_parameter ':' type_parameter_constraints
    ;

type_parameter_constraints
    : primary_constraint
    | secondary_constraints
    | constructor_constraint
    | primary_constraint ',' secondary_constraints
    | primary_constraint ',' constructor_constraint
    | secondary_constraints ',' constructor_constraint
    | primary_constraint ',' secondary_constraints ',' constructor_constraint
    ;

primary_constraint
    : class_type
    | 'class'
    | 'struct'
    ;

secondary_constraints
    : interface_type
    | type_parameter
    | secondary_constraints ',' interface_type
    | secondary_constraints ',' type_parameter
    ;

constructor_constraint
    : 'new' '(' ')'
    ;

type_parameter_constraints_clauseは、トークン whereで構成され、その後に型パラメーターの名前が続き、その後にコロンとその型パラメーターの制約のリストが続きます。Each type_parameter_constraints_clause consists of the token where, followed by the name of a type parameter, followed by a colon and the list of constraints for that type parameter. 型パラメーターごとに1つの where 句を指定できます。また、where 句は任意の順序で一覧表示できます。There can be at most one where clause for each type parameter, and the where clauses can be listed in any order. プロパティアクセサーの get および set トークンと同様、where トークンはキーワードではありません。Like the get and set tokens in a property accessor, the where token is not a keyword.

where 句に指定されている制約の一覧には、次のいずれかのコンポーネントを含めることができます。この順序では、1つのプライマリ制約、1つ以上のセカンダリ制約、コンストラクター制約、new()です。The list of constraints given in a where clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, new().

プライマリ制約は、クラス型、参照型の制約class、または値型の制約structにすることができます。A primary constraint can be a class type or the reference type constraint class or the value type constraint struct. セカンダリ制約は、 type_parameterまたはinterface_typeにすることができます。A secondary constraint can be a type_parameter or interface_type.

参照型の制約は、型パラメーターに使用される型引数が参照型である必要があることを指定します。The reference type constraint specifies that a type argument used for the type parameter must be a reference type. すべてのクラス型、インターフェイス型、デリゲート型、配列型、および参照型として知られる型パラメーターは、この制約を満たしています。All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.

値型の制約は、型パラメーターに使用される型引数が null 非許容の値型である必要があることを指定します。The value type constraint specifies that a type argument used for the type parameter must be a non-nullable value type. Null 非許容の構造体型、列挙型、および値型の制約を持つ型パラメーターは、この制約を満たしています。All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. 値型として分類されていますが、null 許容型 (Null 許容型) は値型の制約を満たしていないことに注意してください。Note that although classified as a value type, a nullable type (Nullable types) does not satisfy the value type constraint. 値型の制約を持つ型パラメーターには、 constructor_constraintを指定することもできません。A type parameter having the value type constraint cannot also have the constructor_constraint.

ポインター型を型引数にすることはできません。また、参照型または値型の制約を満たしているとは見なされません。Pointer types are never allowed to be type arguments and are not considered to satisfy either the reference type or value type constraints.

制約がクラス型、インターフェイス型、または型パラメーターである場合、その型は、その型パラメーターに使用されるすべての型引数がをサポートする必要がある最小の "基本型" を指定します。If a constraint is a class type, an interface type, or a type parameter, that type specifies a minimal "base type" that every type argument used for that type parameter must support. 構築された型またはジェネリックメソッドを使用する場合は、コンパイル時に型パラメーターの制約に対して型引数がチェックされます。Whenever a constructed type or generic method is used, the type argument is checked against the constraints on the type parameter at compile-time. 指定された型引数は、「制約を満たす」で説明されている条件を満たす必要があります。The type argument supplied must satisfy the conditions described in Satisfying constraints.

Class_type制約は、次の規則を満たしている必要があります。A class_type constraint must satisfy the following rules:

  • 型はクラス型である必要があります。The type must be a class type.
  • 型を sealedにすることはできません。The type must not be sealed.
  • 型は、System.ArraySystem.DelegateSystem.Enum、または System.ValueTypeのいずれの型でもない必要があります。The type must not be one of the following types: System.Array, System.Delegate, System.Enum, or System.ValueType.
  • 型を objectにすることはできません。The type must not be object. すべての型は objectから派生するため、このような制約は、許可されている場合は効果がありません。Because all types derive from object, such a constraint would have no effect if it were permitted.
  • 特定の型パラメーターに対して最大1つの制約をクラス型にすることができます。At most one constraint for a given type parameter can be a class type.

Interface_type制約として指定する型は、次の規則を満たしている必要があります。A type specified as an interface_type constraint must satisfy the following rules:

  • 型はインターフェイス型である必要があります。The type must be an interface type.
  • 指定された where 句では、型を複数回指定することはできません。A type must not be specified more than once in a given where clause.

どちらの場合も、制約には、関連付けられている型またはメソッドの宣言の型パラメーターを構築型の一部として含めることができ、宣言された型を含めることができます。In either case, the constraint can involve any of the type parameters of the associated type or method declaration as part of a constructed type, and can involve the type being declared.

型パラメーターの制約として指定されたクラスまたはインターフェイスの型は、宣言するジェネリック型またはメソッドと同じように、少なくともアクセス可能な (アクセシビリティ制約) 必要があります。Any class or interface type specified as a type parameter constraint must be at least as accessible (Accessibility constraints) as the generic type or method being declared.

Type_parameter制約として指定する型は、次の規則を満たしている必要があります。A type specified as a type_parameter constraint must satisfy the following rules:

  • 型は型パラメーターでなければなりません。The type must be a type parameter.
  • 指定された where 句では、型を複数回指定することはできません。A type must not be specified more than once in a given where clause.

さらに、型パラメーターの依存関係グラフに循環がない必要があります。依存関係は、によって定義される推移的な関係です。In addition there must be no cycles in the dependency graph of type parameters, where dependency is a transitive relation defined by:

  • 型パラメーター T が型パラメーターの制約として使用されている場合 S STに依存します。If a type parameter T is used as a constraint for type parameter S then S depends on T.
  • 型パラメーター S が型パラメーター T に依存し、T が型 U パラメーターに依存している場合、SUに依存します。If a type parameter S depends on a type parameter T and T depends on a type parameter U then S depends on U.

この関係により、型パラメーターが自身に依存している (直接または間接的に) ことを前提としたコンパイル時エラーになります。Given this relation, it is a compile-time error for a type parameter to depend on itself (directly or indirectly).

制約は、依存する型パラメーターの間で一貫している必要があります。Any constraints must be consistent among dependent type parameters. 型パラメーター S が型パラメーターに依存する場合 T 次のようになります。If type parameter S depends on type parameter T then:

  • T には値型の制約を指定できません。T must not have the value type constraint. それ以外の場合、T は実質的にシールされるため、STと同じ型である必要があります。これにより、2つの型パラメーターは不要になります。Otherwise, T is effectively sealed so S would be forced to be the same type as T, eliminating the need for two type parameters.
  • S に値型の制約がある場合は、Tclass_type制約を指定することはできません。If S has the value type constraint then T must not have a class_type constraint.
  • Sclass_typeA 制約があり、Tclass_typeの制約がある場合は、B から A への id 変換または暗黙の参照変換が B になる必要があります。B``AIf S has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.
  • S 型パラメーター U にも依存し、Uclass_typeの制約があり、AT の制約がある場合は、class_type から B への id 変換または暗黙の参照変換が A になる必要があります。B``B``AIf S also depends on type parameter U and U has a class_type constraint A and T has a class_type constraint B then there must be an identity conversion or implicit reference conversion from A to B or an implicit reference conversion from B to A.

S が値型の制約を持ち、T 参照型の制約を持つようにするために有効です。It is valid for S to have the value type constraint and T to have the reference type constraint. これにより、System.ObjectSystem.ValueTypeSystem.Enum、および任意のインターフェイス型に T が制限されます。Effectively this limits T to the types System.Object, System.ValueType, System.Enum, and any interface type.

型パラメーターのwhere new() 句にコンストラクターの制約 (フォームがある) が含まれている場合は、演算子を使用して、型のインスタンス (newオブジェクト作成式) を作成することができます。If the where clause for a type parameter includes a constructor constraint (which has the form new()), it is possible to use the new operator to create instances of the type (Object creation expressions). コンストラクター制約のある型パラメーターに使用されるすべての型引数には、パブリックなパラメーターなしのコンストラクターが必要です (このコンストラクターは、任意の値型に対して暗黙的に存在します)。または、値型の制約またはコンストラクターの制約を持つ型パラメーターであることAny type argument used for a type parameter with a constructor constraint must have a public parameterless constructor (this constructor implicitly exists for any value type) or be a type parameter having the value type constraint or constructor constraint (see Type parameter constraints for details).

制約の例を次に示します。The following are examples of constraints:

interface IPrintable
{
    void Print();
}

interface IComparable<T>
{
    int CompareTo(T value);
}

interface IKeyProvider<T>
{
    T GetKey();
}

class Printer<T> where T: IPrintable {...}

class SortedList<T> where T: IComparable<T> {...}

class Dictionary<K,V>
    where K: IComparable<K>
    where V: IPrintable, IKeyProvider<K>, new()
{
    ...
}

次の例では、型パラメーターの依存関係グラフで循環が発生するため、エラーが発生しています。The following example is in error because it causes a circularity in the dependency graph of the type parameters:

class Circular<S,T>
    where S: T
    where T: S                // Error, circularity in dependency graph
{
    ...
}

次の例は、その他の無効な状況を示しています。The following examples illustrate additional invalid situations:

class Sealed<S,T>
    where S: T
    where T: struct        // Error, T is sealed
{
    ...
}

class A {...}

class B {...}

class Incompat<S,T>
    where S: A, T
    where T: B                // Error, incompatible class-type constraints
{
    ...
}

class StructWithClass<S,T,U>
    where S: struct, T
    where T: U
    where U: A                // Error, A incompatible with struct
{
    ...
}

T 型パラメーターの有効な基本クラスは次のように定義されています。The effective base class of a type parameter T is defined as follows:

  • T に primary 制約または型パラメーター制約がない場合、その有効な基本クラスは objectです。If T has no primary constraints or type parameter constraints, its effective base class is object.
  • T に値型の制約がある場合、その有効な基本クラスは System.ValueTypeです。If T has the value type constraint, its effective base class is System.ValueType.
  • Tclass_type C 制約はありますがtype_parameter制約はありませんが、その有効な基本クラスは Cです。If T has a class_type constraint C but no type_parameter constraints, its effective base class is C.
  • Tclass_type制約がなく、1つ以上のtype_parameter制約がある場合、その有効な基本クラスは、そのtype_parameter制約の有効な基本クラスのセットに含まれる最も内側の型 (リフトされた変換演算子) になります。If T has no class_type constraint but has one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set of effective base classes of its type_parameter constraints. 一貫性規則により、このような最も包含型が存在することが保証されます。The consistency rules ensure that such a most encompassed type exists.
  • Tclass_type制約と1つ以上のtype_parameter制約の両方がある場合、その有効な基本クラスは、Tclass_type制約とそのtype_parameter制約の有効な基本クラスで構成される、セット内の最も包含型 (リフトされた変換演算子) です。If T has both a class_type constraint and one or more type_parameter constraints, its effective base class is the most encompassed type (Lifted conversion operators) in the set consisting of the class_type constraint of T and the effective base classes of its type_parameter constraints. 一貫性規則により、このような最も包含型が存在することが保証されます。The consistency rules ensure that such a most encompassed type exists.
  • T が参照型の制約を持ち、 class_typeの制約がない場合、その有効な基本クラスは objectます。If T has the reference type constraint but no class_type constraints, its effective base class is object.

これらの規則の目的のために、T にvalue_typeの制約 V がある場合は、代わりにを使用して、 class_typeである V の最も限定的な基本型を使用します。For the purpose of these rules, if T has a constraint V that is a value_type, use instead the most specific base type of V that is a class_type. これは明示的に指定された制約では発生しませんが、ジェネリックメソッドの制約が、オーバーライドするメソッドの宣言またはインターフェイスメソッドの明示的な実装によって暗黙的に継承される場合に発生する可能性があります。This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.

これらの規則は、有効な基本クラスが常にclass_typeであることを確認します。These rules ensure that the effective base class is always a class_type.

T 型パラメーターの有効なインターフェイスセットは、次のように定義されます。The effective interface set of a type parameter T is defined as follows:

  • Tsecondary_constraintsがない場合、その有効なインターフェイスセットは空になります。If T has no secondary_constraints, its effective interface set is empty.
  • T interface_typeに制約があり、 type_parameter制約がない場合、その有効なインターフェイスセットはinterface_type制約のセットになります。If T has interface_type constraints but no type_parameter constraints, its effective interface set is its set of interface_type constraints.
  • Tinterface_type制約がなく、 type_parameter制約がある場合、その有効なインターフェイスセットは、そのtype_parameter制約の有効なインターフェイスセットの和集合になります。If T has no interface_type constraints but has type_parameter constraints, its effective interface set is the union of the effective interface sets of its type_parameter constraints.
  • Tinterface_typeの制約とtype_parameterの制約の両方がある場合、その有効なインターフェイスセットは、一連のinterface_type制約とそのtype_parameter制約の有効なインターフェイスセットの和集合になります。If T has both interface_type constraints and type_parameter constraints, its effective interface set is the union of its set of interface_type constraints and the effective interface sets of its type_parameter constraints.

参照型の制約がある場合、またはその有効な基本クラスが object または System.ValueTypeでない場合、型パラメーターは参照型であると認識されます。A type parameter is known to be a reference type if it has the reference type constraint or its effective base class is not object or System.ValueType.

制約付きの型パラメーター型の値を使用して、制約によって暗黙的に指定されたインスタンスメンバーにアクセスできます。Values of a constrained type parameter type can be used to access the instance members implied by the constraints. この例では、In the example

interface IPrintable
{
    void Print();
}

class Printer<T> where T: IPrintable
{
    void PrintOne(T x) {
        x.Print();
    }
}

IPrintable のメソッドは、x で直接呼び出すことができます。 T は常に IPrintableを実装するように制約されているためです。the methods of IPrintable can be invoked directly on x because T is constrained to always implement IPrintable.

クラス本体Class body

クラスのclass_bodyは、そのクラスのメンバーを定義します。The class_body of a class defines the members of that class.

class_body
    : '{' class_member_declaration* '}'
    ;

部分型Partial types

型宣言は、複数の部分型宣言にまたがって分割できます。A type declaration can be split across multiple partial type declarations. 型宣言は、このセクションの規則に従ってパートから構築されます。とは、プログラムのコンパイル時および実行時の処理中に、単一の宣言として扱われます。The type declaration is constructed from its parts by following the rules in this section, whereupon it is treated as a single declaration during the remainder of the compile-time and run-time processing of the program.

Class_declarationstruct_declarationまたはinterface_declarationは、partial 修飾子が含まれている場合、部分型宣言を表します。A class_declaration, struct_declaration or interface_declaration represents a partial type declaration if it includes a partial modifier. partial はキーワードではなく、修飾子としてのみ機能します。これは、classキーワードの1つの直前、型宣言内、struct または interface、またはメソッド宣言内の型 void の前に記述されている場合にのみ機能します。partial is not a keyword, and only acts as a modifier if it appears immediately before one of the keywords class, struct or interface in a type declaration, or before the type void in a method declaration. その他のコンテキストでは、通常の識別子として使用できます。In other contexts it can be used as a normal identifier.

部分型の宣言の各部分には、partial 修飾子を含める必要があります。Each part of a partial type declaration must include a partial modifier. 同じ名前を持ち、他の部分と同じ名前空間または型宣言で宣言されている必要があります。It must have the same name and be declared in the same namespace or type declaration as the other parts. partial 修飾子は、型宣言の追加部分が別の場所に存在する可能性があることを示しますが、そのような追加の部分の存在は要件ではありません。これは、1つの宣言で partial 修飾子を含む型に対して有効です。The partial modifier indicates that additional parts of the type declaration may exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for a type with a single declaration to include the partial modifier.

部分型のすべての部分を一緒にコンパイルして、コンパイル時にパートを1つの型宣言にマージできるようにする必要があります。All parts of a partial type must be compiled together such that the parts can be merged at compile-time into a single type declaration. 部分型では、コンパイル済みの型を拡張することはできません。Partial types specifically do not allow already compiled types to be extended.

入れ子になった型は、partial 修飾子を使用して複数の部分で宣言できます。Nested types may be declared in multiple parts by using the partial modifier. 通常、含んでいる型は partial を使用して宣言され、入れ子にされた型の各部分は、含んでいる型の別の部分で宣言されます。Typically, the containing type is declared using partial as well, and each part of the nested type is declared in a different part of the containing type.

partial 修飾子は、デリゲートまたは列挙型の宣言では許可されていません。The partial modifier is not permitted on delegate or enum declarations.

属性Attributes

部分型の属性は、各部分の属性を指定しない順序で組み合わせることによって決定されます。The attributes of a partial type are determined by combining, in an unspecified order, the attributes of each of the parts. 属性が複数の部分に配置されている場合は、その型に対して属性を複数回指定することと同じです。If an attribute is placed on multiple parts, it is equivalent to specifying the attribute multiple times on the type. たとえば、次の2つの部分があります。For example, the two parts:

[Attr1, Attr2("hello")]
partial class A {}

[Attr3, Attr2("goodbye")]
partial class A {}

は、次のような宣言と同じです。are equivalent to a declaration such as:

[Attr1, Attr2("hello"), Attr3, Attr2("goodbye")]
class A {}

型パラメーターの属性は、同様の方法で結合されます。Attributes on type parameters combine in a similar fashion.

修飾子Modifiers

部分型の宣言にアクセシビリティの仕様 (publicprotectedinternal、および private の修飾子) が含まれている場合、アクセシビリティの仕様を含むその他すべての部分に同意する必要があります。When a partial type declaration includes an accessibility specification (the public, protected, internal, and private modifiers) it must agree with all other parts that include an accessibility specification. 部分型の一部にアクセシビリティの指定が含まれていない場合、型には、適切な既定のアクセシビリティ (宣言されたアクセシビリティ) が与えられます。If no part of a partial type includes an accessibility specification, the type is given the appropriate default accessibility (Declared accessibility).

入れ子になった型の1つ以上の部分宣言に new 修飾子が含まれる場合、入れ子にされた型が継承されたメンバーを隠ぺいする (継承によって隠ぺいされる) 場合、警告は報告されません。If one or more partial declarations of a nested type include a new modifier, no warning is reported if the nested type hides an inherited member (Hiding through inheritance).

クラスの1つ以上の部分宣言に abstract 修飾子が含まれている場合、クラスは抽象 (抽象クラス) と見なされます。If one or more partial declarations of a class include an abstract modifier, the class is considered abstract (Abstract classes). それ以外の場合、クラスは非抽象であると見なされます。Otherwise, the class is considered non-abstract.

クラスの1つ以上の部分宣言に sealed 修飾子が含まれている場合、クラスは sealed (sealed クラス) と見なされます。If one or more partial declarations of a class include a sealed modifier, the class is considered sealed (Sealed classes). それ以外の場合、クラスはシールされていないと見なされます。Otherwise, the class is considered unsealed.

クラスに abstract と sealed の両方を指定することはできません。Note that a class cannot be both abstract and sealed.

部分型宣言で修飾子を使用すると、その特定の部分だけがunsafeコンテキスト(unsafeUnsafe コンテキスト)と見なされます。When the unsafe modifier is used on a partial type declaration, only that particular part is considered an unsafe context (Unsafe contexts).

型パラメーターと制約Type parameters and constraints

ジェネリック型が複数の部分で宣言されている場合、各部分は型パラメーターを指定する必要があります。If a generic type is declared in multiple parts, each part must state the type parameters. 各部分には、同じ数の型パラメーターと、それぞれの型パラメーターに対して同じ名前を指定する必要があります。Each part must have the same number of type parameters, and the same name for each type parameter, in order.

部分的なジェネリック型の宣言に制約 (where 句) が含まれている場合、制約は、制約を含むその他すべての部分と一致する必要があります。When a partial generic type declaration includes constraints (where clauses), the constraints must agree with all other parts that include constraints. 具体的には、制約を含む各部分は、同じ型パラメーターのセットに対する制約を持つ必要があります。また、各型パラメーターには、primary、secondary、およびコンストラクターの各制約のセットが同等である必要があります。Specifically, each part that includes constraints must have constraints for the same set of type parameters, and for each type parameter the sets of primary, secondary, and constructor constraints must be equivalent. 同じメンバーが含まれている場合、2つの制約セットは同等です。Two sets of constraints are equivalent if they contain the same members. 部分的なジェネリック型の一部で型パラメーターの制約が指定されていない場合、型パラメーターは制約なしと見なされます。If no part of a partial generic type specifies type parameter constraints, the type parameters are considered unconstrained.

The example

partial class Dictionary<K,V>
    where K: IComparable<K>
    where V: IKeyProvider<K>, IPersistable
{
    ...
}

partial class Dictionary<K,V>
    where V: IPersistable, IKeyProvider<K>
    where K: IComparable<K>
{
    ...
}

partial class Dictionary<K,V>
{
    ...
}

は、制約を含む部分 (最初の2つ) が、同じ型パラメーターのセットに対して同じ primary、secondary、およびコンストラクターの制約のセットを効果的に指定するため、正しいです。is correct because those parts that include constraints (the first two) effectively specify the same set of primary, secondary, and constructor constraints for the same set of type parameters, respectively.

基底クラスBase class

部分クラスの宣言に基底クラスの指定が含まれている場合、基底クラスの指定を含む他のすべての部分に同意する必要があります。When a partial class declaration includes a base class specification it must agree with all other parts that include a base class specification. 部分クラスの一部に基底クラスの指定が含まれていない場合、基本クラスは System.Object (基底クラス) になります。If no part of a partial class includes a base class specification, the base class becomes System.Object (Base classes).

基本インターフェイスBase interfaces

複数の部分で宣言された型の基本インターフェイスのセットは、各部分で指定された基本インターフェイスの和集合です。The set of base interfaces for a type declared in multiple parts is the union of the base interfaces specified on each part. 特定の基本インターフェイスには、各部分で1回だけ名前を付けることができますが、複数の部分で同じ基本インターフェイスに名前を付けることができます。A particular base interface may only be named once on each part, but it is permitted for multiple parts to name the same base interface(s). 特定の基本インターフェイスのメンバーの実装は1つだけ必要です。There must only be one implementation of the members of any given base interface.

この例では、In the example

partial class C: IA, IB {...}

partial class C: IC {...}

partial class C: IA, IB {...}

クラス C の基本インターフェイスのセットは、IAIB、および ICです。the set of base interfaces for class C is IA, IB, and IC.

通常、各部分は、その部分で宣言されたインターフェイスの実装を提供します。ただし、これは要件ではありません。Typically, each part provides an implementation of the interface(s) declared on that part; however, this is not a requirement. パートは、別の部分で宣言されたインターフェイスの実装を提供する場合があります。A part may provide the implementation for an interface declared on a different part:

partial class X
{
    int IComparable.CompareTo(object o) {...}
}

partial class X: IComparable
{
    ...
}

メンバーMembers

部分メソッド (部分メソッド) を除き、複数の部分で宣言された型のメンバーのセットは、単に各部分で宣言されたメンバーのセットの和集合になります。With the exception of partial methods (Partial methods), the set of members of a type declared in multiple parts is simply the union of the set of members declared in each part. 型宣言のすべての部分の本体は同じ宣言空間 (宣言) を共有し、各メンバー (スコープ) のスコープはすべての部分の本体に拡張されます。The bodies of all parts of the type declaration share the same declaration space (Declarations), and the scope of each member (Scopes) extends to the bodies of all the parts. メンバーのアクセシビリティドメインには、それを囲む型のすべての部分が常に含まれます。あるパートで宣言された private メンバーは、別のパートから自由にアクセスできます。The accessibility domain of any member always includes all the parts of the enclosing type; a private member declared in one part is freely accessible from another part. 型の複数の部分で同じメンバーを宣言する場合、そのメンバーが partial 修飾子を持つ型である場合を除き、コンパイル時にエラーが発生します。It is a compile-time error to declare the same member in more than one part of the type, unless that member is a type with the partial modifier.

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int y;
    }
}

partial class A
{
    int x;                     // Error, cannot declare x more than once

    partial class Inner        // Ok, Inner is a partial type
    {
        int z;
    }
}

型内のメンバーの順序付けは、コードにC#とってはあまり重要ではありませんが、他の言語や環境とのやり取りには大きな意味があります。The ordering of members within a type is rarely significant to C# code, but may be significant when interfacing with other languages and environments. このような場合、複数の部分で宣言された型内のメンバーの順序は未定義です。In these cases, the ordering of members within a type declared in multiple parts is undefined.

部分メソッドPartial methods

部分メソッドは、型宣言の1つの部分で定義し、別ので実装することができます。Partial methods can be defined in one part of a type declaration and implemented in another. 実装は省略可能です。部分メソッドを実装している部分がない場合は、部分メソッドの宣言とその部分のすべての呼び出しが、その部分の組み合わせによって生成される型宣言から削除されます。The implementation is optional; if no part implements the partial method, the partial method declaration and all calls to it are removed from the type declaration resulting from the combination of the parts.

部分メソッドはアクセス修飾子を定義できませんが、暗黙的に privateます。Partial methods cannot define access modifiers, but are implicitly private. 戻り値の型は voidである必要があり、そのパラメーターには out 修飾子を指定できません。Their return type must be void, and their parameters cannot have the out modifier. 識別子 partial は、void 型の直前に出現する場合にのみ、メソッド宣言で特別なキーワードとして認識されます。それ以外の場合は、通常の識別子として使用できます。The identifier partial is recognized as a special keyword in a method declaration only if it appears right before the void type; otherwise it can be used as a normal identifier. 部分メソッドは、インターフェイスメソッドを明示的に実装することはできません。A partial method cannot explicitly implement interface methods.

部分メソッド宣言には2種類あります。メソッド宣言の本体がセミコロンの場合、宣言は部分メソッド宣言の定義と呼ばれます。There are two kinds of partial method declarations: If the body of the method declaration is a semicolon, the declaration is said to be a defining partial method declaration. 本文がブロックとして指定されている場合、宣言は部分メソッド宣言の実装と呼ばれます。If the body is given as a block, the declaration is said to be an implementing partial method declaration. 型宣言の一部では、特定のシグネチャを持つ部分メソッド宣言を1つだけ定義できます。また、特定のシグネチャを持つ実装部分メソッド宣言は1つだけです。Across the parts of a type declaration there can be only one defining partial method declaration with a given signature, and there can be only one implementing partial method declaration with a given signature. 実装部分メソッド宣言が指定されている場合は、対応する部分メソッド宣言を定義する必要があり、宣言は次のように指定されている必要があります。If an implementing partial method declaration is given, a corresponding defining partial method declaration must exist, and the declarations must match as specified in the following:

  • 宣言には、同じ修飾子 (必ずしも同じ順序ではありません)、メソッド名、型パラメーターの数、およびパラメーターの数を指定する必要があります。The declarations must have the same modifiers (although not necessarily in the same order), method name, number of type parameters and number of parameters.
  • 宣言内の対応するパラメーターは、同じ修飾子を持つ必要があります (必ずしも同じ順序ではありません)。また、型パラメーター名のモジュロが異なる場合もあります。Corresponding parameters in the declarations must have the same modifiers (although not necessarily in the same order) and the same types (modulo differences in type parameter names).
  • 宣言内の対応する型パラメーターは、同じ制約を持つ必要があります (型パラメーター名の剰余の違い)。Corresponding type parameters in the declarations must have the same constraints (modulo differences in type parameter names).

部分メソッド宣言の実装は、対応する部分メソッド宣言を定義するのと同じ部分に記述できます。An implementing partial method declaration can appear in the same part as the corresponding defining partial method declaration.

オーバーロードの解決に参加するのは、部分メソッドの定義のみです。Only a defining partial method participates in overload resolution. したがって、実装宣言が指定されているかどうかにかかわらず、呼び出し式は部分メソッドの呼び出しに解決される可能性があります。Thus, whether or not an implementing declaration is given, invocation expressions may resolve to invocations of the partial method. 部分メソッドは常に voidを返すため、このような呼び出し式は常に式ステートメントになります。Because a partial method always returns void, such invocation expressions will always be expression statements. さらに、部分メソッドは暗黙的に privateされるため、このようなステートメントは、部分メソッドが宣言されている型宣言のいずれかの部分で常に発生します。Furthermore, because a partial method is implicitly private, such statements will always occur within one of the parts of the type declaration within which the partial method is declared.

部分型宣言の一部に、特定の部分メソッドの実装宣言が含まれていない場合、その部分メソッドを呼び出す式ステートメントは、結合された型宣言から単純に削除されます。If no part of a partial type declaration contains an implementing declaration for a given partial method, any expression statement invoking it is simply removed from the combined type declaration. したがって、構成式を含む呼び出し式は、実行時に効果がありません。Thus the invocation expression, including any constituent expressions, has no effect at run-time. 部分メソッド自体も削除され、結合された型宣言のメンバーにはなりません。The partial method itself is also removed and will not be a member of the combined type declaration.

実装宣言が特定の部分メソッドに存在する場合は、部分メソッドの呼び出しが保持されます。If an implementing declaration exist for a given partial method, the invocations of the partial methods are retained. 部分メソッドは、次の点を除いて、部分メソッド宣言の実装に似たメソッド宣言になります。The partial method gives rise to a method declaration similar to the implementing partial method declaration except for the following:

  • partial 修飾子は含まれていませんThe partial modifier is not included
  • 結果として得られるメソッドの宣言の属性は、定義の属性と実装部分メソッドの宣言を、指定されていない順序で結合したものです。The attributes in the resulting method declaration are the combined attributes of the defining and the implementing partial method declaration in unspecified order. 重複は削除されません。Duplicates are not removed.
  • 結果として得られるメソッド宣言のパラメーターの属性は、定義の対応するパラメーターの属性と、部分メソッドの実装を指定しない順序での実装の属性を組み合わせたものです。The attributes on the parameters of the resulting method declaration are the combined attributes of the corresponding parameters of the defining and the implementing partial method declaration in unspecified order. 重複は削除されません。Duplicates are not removed.

実装宣言ではなく、定義宣言が部分メソッド M に対して指定されている場合、次の制限が適用されます。If a defining declaration but not an implementing declaration is given for a partial method M, the following restrictions apply:

部分メソッドは、1つの型宣言の一部を使用して、ツールによって生成された別のパートの動作をカスタマイズできるようにする場合に便利です。Partial methods are useful for allowing one part of a type declaration to customize the behavior of another part, e.g., one that is generated by a tool. 次の部分クラス宣言について考えてみます。Consider the following partial class declaration:

partial class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    partial void OnNameChanging(string newName);

    partial void OnNameChanged();
}

このクラスが他の部分なしでコンパイルされた場合、定義部分メソッド宣言とその呼び出しは削除され、結果として得られるクラス宣言は次のようになります。If this class is compiled without any other parts, the defining partial method declarations and their invocations will be removed, and the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

    public string Name {
        get { return name; }
        set { name = value; }
    }
}

ただし、部分メソッドの実装宣言を提供する別のパートが指定されているとします。Assume that another part is given, however, which provides implementing declarations of the partial methods:

partial class Customer
{
    partial void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    partial void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

次に、結果として得られる結合クラスの宣言は、次のようになります。Then the resulting combined class declaration will be equivalent to the following:

class Customer
{
    string name;

    public string Name {
        get { return name; }
        set {
            OnNameChanging(value);
            name = value;
            OnNameChanged();
        }

    }

    void OnNameChanging(string newName)
    {
        Console.WriteLine("Changing " + name + " to " + newName);
    }

    void OnNameChanged()
    {
        Console.WriteLine("Changed to " + name);
    }
}

名前のバインドName binding

拡張可能な型の各部分は同じ名前空間内で宣言する必要がありますが、通常、各部分は異なる名前空間宣言内に記述されます。Although each part of an extensible type must be declared within the same namespace, the parts are typically written within different namespace declarations. したがって、各部分に異なる using ディレクティブ (ディレクティブを使用) が存在する場合があります。Thus, different using directives (Using directives) may be present for each part. 1つの部分で単純な名前 (型の推定) を解釈する場合、その部分を囲む名前空間宣言の using ディレクティブだけが考慮されます。When interpreting simple names (Type inference) within one part, only the using directives of the namespace declaration(s) enclosing that part are considered. これにより、異なる部分で異なる意味を持つ同じ識別子が生成される可能性があります。This may result in the same identifier having different meanings in different parts:

namespace N
{
    using List = System.Collections.ArrayList;

    partial class A
    {
        List x;                // x has type System.Collections.ArrayList
    }
}

namespace N
{
    using List = Widgets.LinkedList;

    partial class A
    {
        List y;                // y has type Widgets.LinkedList
    }
}

クラス メンバーClass members

クラスのメンバーは、そのclass_member_declarationによって導入されたメンバーと、直接基底クラスから継承されたメンバーで構成されます。The members of a class consist of the members introduced by its class_member_declarations and the members inherited from the direct base class.

class_member_declaration
    : constant_declaration
    | field_declaration
    | method_declaration
    | property_declaration
    | event_declaration
    | indexer_declaration
    | operator_declaration
    | constructor_declaration
    | destructor_declaration
    | static_constructor_declaration
    | type_declaration
    ;

クラス型のメンバーは、次のカテゴリに分類されます。The members of a class type are divided into the following categories:

  • 定数。クラス (定数) に関連付けられている定数値を表します。Constants, which represent constant values associated with the class (Constants).
  • フィールド。クラス (フィールド) の変数です。Fields, which are the variables of the class (Fields).
  • メソッド。クラスによって実行できる計算とアクションを実装します (メソッド)。Methods, which implement the computations and actions that can be performed by the class (Methods).
  • プロパティ。名前付きの特性、およびこれらの特性 (プロパティ) の読み取りと書き込みに関連するアクションを定義します。Properties, which define named characteristics and the actions associated with reading and writing those characteristics (Properties).
  • イベント。クラス (イベント) によって生成される通知を定義します。Events, which define notifications that can be generated by the class (Events).
  • インデクサーは、クラスのインスタンスが配列 (インデクサー) と同じ方法で (構文的に) インデックスを作成できるようにします。Indexers, which permit instances of the class to be indexed in the same way (syntactically) as arrays (Indexers).
  • 演算子。クラスのインスタンスに適用できる式演算子を定義します (演算子)。Operators, which define the expression operators that can be applied to instances of the class (Operators).
  • クラスのインスタンスを初期化するために必要なアクションを実装するインスタンスコンストラクター (インスタンスコンストラクター)Instance constructors, which implement the actions required to initialize instances of the class (Instance constructors)
  • デストラクターは、クラスのインスタンスが完全に破棄 (デストラクター) される前に実行されるアクションを実装します。Destructors, which implement the actions to be performed before instances of the class are permanently discarded (Destructors).
  • 静的コンストラクター。クラス自体を初期化するために必要なアクション (静的コンストラクター) を実装します。Static constructors, which implement the actions required to initialize the class itself (Static constructors).
  • 型。クラス (入れ子にされた) に対してローカルな型を表します。Types, which represent the types that are local to the class (Nested types).

実行可能コードを含むことができるメンバーは、クラス型の関数メンバーと総称されます。Members that can contain executable code are collectively known as the function members of the class type. クラス型の関数メンバーは、そのクラス型のメソッド、プロパティ、イベント、インデクサー、演算子、インスタンスコンストラクター、デストラクター、および静的コンストラクターです。The function members of a class type are the methods, properties, events, indexers, operators, instance constructors, destructors, and static constructors of that class type.

Class_declarationによって新しい宣言空間 (宣言) が作成され、 class_declarationにすぐに含まれるclass_member_declarationが、この宣言空間に新しいメンバーを導入します。A class_declaration creates a new declaration space (Declarations), and the class_member_declarations immediately contained by the class_declaration introduce new members into this declaration space. Class_member_declarations には、次の規則が適用されます。The following rules apply to class_member_declarations:

  • インスタンスコンストラクター、デストラクター、および静的コンストラクターには、すぐ外側のクラスと同じ名前を付ける必要があります。Instance constructors, destructors and static constructors must have the same name as the immediately enclosing class. 他のすべてのメンバーには、すぐに外側のクラスの名前とは異なる名前を付ける必要があります。All other members must have names that differ from the name of the immediately enclosing class.
  • 定数、フィールド、プロパティ、イベント、または型の名前は、同じクラスで宣言されている他のすべてのメンバーの名前と異なる必要があります。The name of a constant, field, property, event, or type must differ from the names of all other members declared in the same class.
  • メソッドの名前は、同じクラスで宣言されている他のすべての非メソッドの名前と異なる必要があります。The name of a method must differ from the names of all other non-methods declared in the same class. さらに、メソッドのシグネチャ (シグネチャとオーバーロード) は、同じクラスで宣言されている他のすべてのメソッドのシグネチャと異なる必要があります。また、同じクラスで宣言された2つのメソッドは、refoutだけが異なるシグネチャを持つことはできません。In addition, the signature (Signatures and overloading) of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.
  • インスタンスコンストラクターのシグネチャは、同じクラスで宣言されている他のすべてのインスタンスコンストラクターのシグネチャと異なる必要があります。また、同じクラスで宣言された2つのコンストラクターは、refoutのみが異なるシグネチャを持つことはできません。The signature of an instance constructor must differ from the signatures of all other instance constructors declared in the same class, and two constructors declared in the same class may not have signatures that differ solely by ref and out.
  • インデクサーのシグネチャは、同じクラスで宣言されている他のすべてのインデクサーのシグネチャと異なる必要があります。The signature of an indexer must differ from the signatures of all other indexers declared in the same class.
  • 演算子のシグネチャは、同じクラスで宣言されている他のすべての演算子のシグネチャと異なる必要があります。The signature of an operator must differ from the signatures of all other operators declared in the same class.

クラス型 (継承) の継承されたメンバーは、クラスの宣言空間の一部ではありません。The inherited members of a class type (Inheritance) are not part of the declaration space of a class. したがって、派生クラスでは、継承されたメンバーと同じ名前またはシグネチャを持つメンバーを宣言できます (これにより、継承されたメンバーは非表示になります)。Thus, a derived class is allowed to declare a member with the same name or signature as an inherited member (which in effect hides the inherited member).

インスタンスの種類The instance type

各クラス宣言には、バインドされた型 (バインドされた型とバインドされていない)、インスタンス型があります。Each class declaration has an associated bound type (Bound and unbound types), the instance type. ジェネリッククラス宣言では、型宣言から構築された型 (構築型) を作成し、指定された各型引数を対応する型パラメーターとして、インスタンス型を作成します。For a generic class declaration, the instance type is formed by creating a constructed type (Constructed types) from the type declaration, with each of the supplied type arguments being the corresponding type parameter. インスタンス型は型パラメーターを使用するため、型パラメーターがスコープ内にある場合にのみ使用できます。つまり、クラス宣言の内部にあります。Since the instance type uses the type parameters, it can only be used where the type parameters are in scope; that is, inside the class declaration. インスタンス型は、クラス宣言内で記述されたコードの this の型です。The instance type is the type of this for code written inside the class declaration. 非ジェネリッククラスの場合、インスタンスの型は単に宣言されたクラスになります。For non-generic classes, the instance type is simply the declared class. 次に、いくつかのクラス宣言とそのインスタンス型を示します。The following shows several class declarations along with their instance types:

class A<T>                           // instance type: A<T>
{
    class B {}                       // instance type: A<T>.B
    class C<U> {}                    // instance type: A<T>.C<U>
}

class D {}                           // instance type: D

構築された型のメンバーMembers of constructed types

構築された型の非継承メンバーは、メンバー宣言内の各type_parameterに対して、構築された型の対応するtype_argumentに代入することによって取得されます。The non-inherited members of a constructed type are obtained by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the constructed type. 置換プロセスは、型宣言のセマンティックの意味に基づいており、単なるテキスト置換ではありません。The substitution process is based on the semantic meaning of type declarations, and is not simply textual substitution.

たとえば、ジェネリッククラス宣言があるとします。For example, given the generic class declaration

class Gen<T,U>
{
    public T[,] a;
    public void G(int i, T t, Gen<U,T> gt) {...}
    public U Prop { get {...} set {...} }
    public int H(double d) {...}
}

構築された型 Gen<int[],IComparable<string>> には、次のメンバーがあります。the constructed type Gen<int[],IComparable<string>> has the following members:

public int[,][] a;
public void G(int i, int[] t, Gen<IComparable<string>,int[]> gt) {...}
public IComparable<string> Prop { get {...} set {...} }
public int H(double d) {...}

ジェネリッククラス宣言のメンバー a の型 Gen は "Tの2次元配列" です。そのため、上記の構築された型のメンバー a の型は、「intの1次元配列の2次元配列」、または「int[,][]」です。The type of the member a in the generic class declaration Gen is "two-dimensional array of T", so the type of the member a in the constructed type above is "two-dimensional array of one-dimensional array of int", or int[,][].

インスタンス関数のメンバー内では、this の型は、包含する宣言のインスタンスの型 (インスタンス型) です。Within instance function members, the type of this is the instance type (The instance type) of the containing declaration.

ジェネリッククラスのすべてのメンバーは、外側の任意のクラスの型パラメーターを直接または構築された型の一部として使用できます。All members of a generic class can use type parameters from any enclosing class, either directly or as part of a constructed type. 実行時に特定のクローズ構築型 (オープン型およびクローズ型) を使用する場合は、型パラメーターを使用するたびに、構築された型に渡される実際の型引数に置き換えられます。When a particular closed constructed type (Open and closed types) is used at run-time, each use of a type parameter is replaced with the actual type argument supplied to the constructed type. 例 :For example:

class C<V>
{
    public V f1;
    public C<V> f2 = null;

    public C(V x) {
        this.f1 = x;
        this.f2 = this;
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>(1);
        Console.WriteLine(x1.f1);        // Prints 1

        C<double> x2 = new C<double>(3.1415);
        Console.WriteLine(x2.f1);        // Prints 3.1415
    }
}

継承Inheritance

クラスは、その直接の基底クラス型のメンバーを継承します。A class inherits the members of its direct base class type. 継承とは、基底クラスのインスタンスコンストラクター、デストラクター、および静的コンストラクターを除く、クラスに直接基底クラス型のすべてのメンバーが暗黙的に含まれることを意味します。Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class. 継承の重要な側面は次のとおりです。Some important aspects of inheritance are:

  • 継承は推移的です。Inheritance is transitive. CBから派生し、BAから派生している場合、C で宣言されたメンバーと B で宣言されているメンバーが継承されます。AIf C is derived from B, and B is derived from A, then C inherits the members declared in B as well as the members declared in A.
  • 派生クラスは、その直接の基底クラスを拡張します。A derived class extends its direct base class. 派生クラスは、継承するメンバーに新しいメンバーを追加できますが、継承されたメンバーの定義を削除することはできません。A derived class can add new members to those it inherits, but it cannot remove the definition of an inherited member.
  • インスタンスコンストラクター、デストラクター、および静的コンストラクターは継承されませんが、宣言されたアクセシビリティ (メンバーアクセス) に関係なく、他のすべてのメンバーはになります。Instance constructors, destructors, and static constructors are not inherited, but all other members are, regardless of their declared accessibility (Member access). ただし、宣言されたアクセシビリティによっては、継承されたメンバーが派生クラスでアクセスできない場合があります。However, depending on their declared accessibility, inherited members might not be accessible in a derived class.
  • 派生クラスは、同じ名前またはシグネチャを持つ新しいメンバーを宣言することで、継承されたメンバーを隠ぺい ( 隠ぺい) できます。A derived class can hide (Hiding through inheritance) inherited members by declaring new members with the same name or signature. ただし、継承されたメンバーを非表示にしても、そのメンバーは削除されません。つまり、派生クラスを通じてそのメンバーに直接アクセスできないだけです。Note however that hiding an inherited member does not remove that member—it merely makes that member inaccessible directly through the derived class.
  • クラスのインスタンスには、クラスとその基本クラスで宣言されたすべてのインスタンスフィールドのセットが含まれています。また、派生クラス型から基本クラス型への暗黙的な変換 (暗黙的な参照変換) も存在します。An instance of a class contains a set of all instance fields declared in the class and its base classes, and an implicit conversion (Implicit reference conversions) exists from a derived class type to any of its base class types. したがって、派生クラスのインスタンスへの参照は、その基底クラスのインスタンスへの参照として処理できます。Thus, a reference to an instance of some derived class can be treated as a reference to an instance of any of its base classes.
  • クラスは、仮想メソッド、プロパティ、インデクサーを宣言でき、派生クラスはこれらの関数メンバーの実装をオーバーライドできます。A class can declare virtual methods, properties, and indexers, and derived classes can override the implementation of these function members. これにより、クラスは、関数メンバー呼び出しによって実行されるアクションが、その関数メンバーの呼び出しに使用されるインスタンスのランタイム型によって異なる場合に、ポリモーフィックな動作を実現できます。This enables classes to exhibit polymorphic behavior wherein the actions performed by a function member invocation varies depending on the run-time type of the instance through which that function member is invoked.

構築されたクラス型の継承されたメンバーは、直接的な基底クラス型 (基底クラス) のメンバーです。これは、 class_base仕様の対応する型パラメーターが出現するたびに、構築された型の型引数を置き換えることによって検出されます。The inherited member of a constructed class type are the members of the immediate base class type (Base classes), which is found by substituting the type arguments of the constructed type for each occurrence of the corresponding type parameters in the class_base specification. これらのメンバーは、メンバー宣言内の各type_parameterに対して、 class_base仕様の対応するtype_argumentという置換によって変換されます。These members, in turn, are transformed by substituting, for each type_parameter in the member declaration, the corresponding type_argument of the class_base specification.

class B<U>
{
    public U F(long index) {...}
}

class D<T>: B<T[]>
{
    public T G(string s) {...}
}

上の例では、構築された型 D<int> には、型パラメーター Tの型引数 int を置き換えることによって取得される非継承メンバー public int G(string s) が含まれています。In the above example, the constructed type D<int> has a non-inherited member public int G(string s) obtained by substituting the type argument int for the type parameter T. D<int> には、Bクラス宣言から継承されたメンバーもあります。D<int> also has an inherited member from the class declaration B. この継承されたメンバーは、基本クラスの指定 B<T[]>Tint を置き換えることによって、D<int> の基底クラス型 B<int[]> を最初に決定することによって決定されます。This inherited member is determined by first determining the base class type B<int[]> of D<int> by substituting int for T in the base class specification B<T[]>. 次に、Bの型引数として、int[]public U F(long index)U に置き換えられ、継承されたメンバー public int[] F(long index)が生成されます。Then, as a type argument to B, int[] is substituted for U in public U F(long index), yielding the inherited member public int[] F(long index).

新しい修飾子The new modifier

Class_member_declarationは、継承されたメンバーと同じ名前またはシグネチャを持つメンバーを宣言できます。A class_member_declaration is permitted to declare a member with the same name or signature as an inherited member. この場合、派生クラスのメンバーは、基底クラスのメンバーを非表示にすると言います。When this occurs, the derived class member is said to hide the base class member. 継承されたメンバーを非表示にすることは、エラーとは見なされませんが、コンパイラによって警告が発行されます。Hiding an inherited member is not considered an error, but it does cause the compiler to issue a warning. 警告を抑制するには、派生クラスメンバーの宣言に、派生メンバーが基本メンバーを非表示にすることを示す new 修飾子を含めることができます。To suppress the warning, the declaration of the derived class member can include a new modifier to indicate that the derived member is intended to hide the base member. このトピックの詳細については、「継承による非表示」を参照してください。This topic is discussed further in Hiding through inheritance.

継承されたメンバーを非表示にしない宣言に new 修飾子が含まれている場合、その効果に対する警告が発行されます。If a new modifier is included in a declaration that doesn't hide an inherited member, a warning to that effect is issued. この警告は、new 修飾子を削除することによって抑制されます。This warning is suppressed by removing the new modifier.

アクセス修飾子Access modifiers

Class_member_declarationには、publicprotected internalprotectedinternal、または privateという5種類の宣言されたアクセシビリティのうちいずれか1つを使用できます。A class_member_declaration can have any one of the five possible kinds of declared accessibility (Declared accessibility): public, protected internal, protected, internal, or private. protected internal の組み合わせを除き、複数のアクセス修飾子を指定するコンパイル時エラーになります。Except for the protected internal combination, it is a compile-time error to specify more than one access modifier. Class_member_declarationにアクセス修飾子が含まれていない場合、private が想定されます。When a class_member_declaration does not include any access modifiers, private is assumed.

構成型Constituent types

メンバーの宣言で使用される型は、そのメンバーの構成型と呼ばれます。Types that are used in the declaration of a member are called the constituent types of that member. 使用可能な構成型は、定数、フィールド、プロパティ、イベント、またはインデクサーの型、メソッドまたは演算子の戻り値の型、およびメソッド、インデクサー、演算子、またはインスタンスコンストラクターのパラメーターの型です。Possible constituent types are the type of a constant, field, property, event, or indexer, the return type of a method or operator, and the parameter types of a method, indexer, operator, or instance constructor. メンバーの構成型は、少なくともそのメンバー自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The constituent types of a member must be at least as accessible as that member itself (Accessibility constraints).

静的メンバーとインスタンスメンバーStatic and instance members

クラスのメンバーは、静的メンバーまたはインスタンスメンバーです。Members of a class are either static members or instance members. 一般に、静的メンバーは、オブジェクト (クラス型のインスタンス) に属しているクラス型およびインスタンスメンバーに属していると考えると便利です。Generally speaking, it is useful to think of static members as belonging to class types and instance members as belonging to objects (instances of class types).

フィールド、メソッド、プロパティ、イベント、演算子、またはコンストラクターの宣言に static 修飾子が含まれている場合は、静的メンバーを宣言します。When a field, method, property, event, operator, or constructor declaration includes a static modifier, it declares a static member. また、定数または型の宣言は、暗黙的に静的メンバーを宣言します。In addition, a constant or type declaration implicitly declares a static member. 静的メンバーには次の特性があります。Static members have the following characteristics:

  • 静的メンバー ME.Mフォームのmember_access (メンバーアクセス) で参照されている場合、EMを含む型を示す必要があります。When a static member M is referenced in a member_access (Member access) of the form E.M, E must denote a type containing M. E がインスタンスを示す場合、コンパイル時エラーになります。It is a compile-time error for E to denote an instance.
  • 静的フィールドは、指定された closed クラス型のすべてのインスタンスによって共有されるストレージの場所を1つだけ識別します。A static field identifies exactly one storage location to be shared by all instances of a given closed class type. 指定されたクローズクラス型のインスタンスの数に関係なく、静的フィールドのコピーは1つしか存在しません。No matter how many instances of a given closed class type are created, there is only ever one copy of a static field.
  • 静的関数メンバー (メソッド、プロパティ、イベント、演算子、またはコンストラクター) は、特定のインスタンスでは動作しません。このような関数メンバーの this を参照するには、コンパイル時エラーになります。A static function member (method, property, event, operator, or constructor) does not operate on a specific instance, and it is a compile-time error to refer to this in such a function member.

フィールド、メソッド、プロパティ、イベント、インデクサー、コンストラクター、またはデストラクターの宣言に static 修飾子が含まれていない場合、インスタンスメンバーが宣言されます。When a field, method, property, event, indexer, constructor, or destructor declaration does not include a static modifier, it declares an instance member. (インスタンスメンバーは非静的メンバーと呼ばれることもあります)。インスタンスメンバーには次の特性があります。(An instance member is sometimes called a non-static member.) Instance members have the following characteristics:

  • インスタンスメンバー ME.Mフォームのmember_access (メンバーアクセス) で参照されている場合、EMを含む型のインスタンスを示す必要があります。When an instance member M is referenced in a member_access (Member access) of the form E.M, E must denote an instance of a type containing M. E が型を表している場合、バインド時エラーになります。It is a binding-time error for E to denote a type.
  • クラスのすべてのインスタンスには、クラスのすべてのインスタンスフィールドの個別のセットが含まれています。Every instance of a class contains a separate set of all instance fields of the class.
  • インスタンス関数メンバー (メソッド、プロパティ、インデクサー、インスタンスコンストラクター、またはデストラクター) は、クラスの特定のインスタンスで動作し、このインスタンスには this (このアクセス) としてアクセスできます。An instance function member (method, property, indexer, instance constructor, or destructor) operates on a given instance of the class, and this instance can be accessed as this (This access).

次の例は、静的メンバーとインスタンスメンバーにアクセスするための規則を示しています。The following example illustrates the rules for accessing static and instance members:

class Test
{
    int x;
    static int y;

    void F() {
        x = 1;            // Ok, same as this.x = 1
        y = 1;            // Ok, same as Test.y = 1
    }

    static void G() {
        x = 1;            // Error, cannot access this.x
        y = 1;            // Ok, same as Test.y = 1
    }

    static void Main() {
        Test t = new Test();
        t.x = 1;          // Ok
        t.y = 1;          // Error, cannot access static member through instance
        Test.x = 1;       // Error, cannot access instance member through type
        Test.y = 1;       // Ok
    }
}

F メソッドは、インスタンス関数メンバーでsimple_name (簡易名) を使用して、インスタンスメンバーと静的メンバーの両方にアクセスできることを示しています。The F method shows that in an instance function member, a simple_name (Simple names) can be used to access both instance members and static members. G メソッドは、静的関数メンバーで、 simple_nameを介してインスタンスメンバーにアクセスするためのコンパイル時エラーであることを示しています。The G method shows that in a static function member, it is a compile-time error to access an instance member through a simple_name. Main メソッドは、 member_access (メンバーアクセス) でインスタンスメンバーにインスタンスを介してアクセスする必要があり、静的メンバーには型を使用してアクセスする必要があることを示しています。The Main method shows that in a member_access (Member access), instance members must be accessed through instances, and static members must be accessed through types.

入れ子にされた型Nested types

クラスまたは構造体の宣言内で宣言された型は、入れ子にされたと呼ばれます。A type declared within a class or struct declaration is called a nested type. コンパイル単位または名前空間内で宣言された型は、入れ子になっていない型と呼ばれます。A type that is declared within a compilation unit or namespace is called a non-nested type.

この例では、In the example

using System;

class A
{
    class B
    {
        static void F() {
            Console.WriteLine("A.B.F");
        }
    }
}

クラス B はクラス A内で宣言されているため、入れ子にされた型です。クラス A はコンパイル単位内で宣言されているので、入れ子になっていない型です。class B is a nested type because it is declared within class A, and class A is a non-nested type because it is declared within a compilation unit.

完全修飾名Fully qualified name

入れ子にされた型の完全修飾名 (完全修飾名) は S.N です。 S は、N が宣言されている型の完全修飾名です。The fully qualified name (Fully qualified names) for a nested type is S.N where S is the fully qualified name of the type in which type N is declared.

アクセシビリティの宣言Declared accessibility

入れ子になっていない型は、public または internal 宣言されたアクセシビリティを持つことができ、既定では internal として宣言されています。Non-nested types can have public or internal declared accessibility and have internal declared accessibility by default. 入れ子にされた型には、これらの形式のアクセシビリティを含めることができます。また、包含する型がクラスまたは構造体であるかどうかによって、宣言されたアクセシビリティの1つ以上の追加の形式を使用できます。Nested types can have these forms of declared accessibility too, plus one or more additional forms of declared accessibility, depending on whether the containing type is a class or struct:

  • クラス内で宣言されている入れ子にされた型は、5つの形式のアクセシビリティ (publicprotected internalprotectedinternal、または private) を持つことができ、他のクラスメンバーと同様に、既定では private 宣言されたアクセシビリティになります。A nested type that is declared in a class can have any of five forms of declared accessibility (public, protected internal, protected, internal, or private) and, like other class members, defaults to private declared accessibility.
  • 構造体で宣言されている入れ子にされた型は、3つの形式のアクセシビリティ (publicinternal、または private) を持つことができ、他の構造体のメンバーと同様に、既定では private 宣言されたアクセシビリティを持つことになります。A nested type that is declared in a struct can have any of three forms of declared accessibility (public, internal, or private) and, like other struct members, defaults to private declared accessibility.

The example

public class List
{
    // Private data structure
    private class Node
    { 
        public object Data;
        public Node Next;

        public Node(object data, Node next) {
            this.Data = data;
            this.Next = next;
        }
    }

    private Node first = null;
    private Node last = null;

    // Public interface
    public void AddToFront(object o) {...}
    public void AddToBack(object o) {...}
    public object RemoveFromFront() {...}
    public object RemoveFromBack() {...}
    public int Count { get {...} }
}

入れ子になったプライベートクラス Nodeを宣言します。declares a private nested class Node.

非表示Hiding

入れ子にされた型では、基本メンバーを非表示にすることができます (名前の非表示)。A nested type may hide (Name hiding) a base member. new 修飾子は入れ子になった型宣言で許可されているため、非表示を明示的に表すことができます。The new modifier is permitted on nested type declarations so that hiding can be expressed explicitly. The example

using System;

class Base
{
    public static void M() {
        Console.WriteLine("Base.M");
    }
}

class Derived: Base 
{
    new public class M 
    {
        public static void F() {
            Console.WriteLine("Derived.M.F");
        }
    }
}

class Test 
{
    static void Main() {
        Derived.M.F();
    }
}

Baseで定義されている M メソッドを非表示にする M 入れ子になったクラスを示します。shows a nested class M that hides the method M defined in Base.

このアクセス権this access

入れ子にされた型とそれを含んでいる型には、 this_access (このアクセス) に関して特別な関係はありません。A nested type and its containing type do not have a special relationship with regard to this_access (This access). 具体的には、入れ子にされた型内の this は、それを含んでいる型のインスタンスメンバーを参照するために使用することはできません。Specifically, this within a nested type cannot be used to refer to instance members of the containing type. 入れ子にされた型が、それを含んでいる型のインスタンスメンバーにアクセスする必要がある場合は、入れ子にされた型のコンストラクター引数として、包含する型のインスタンスの this を指定することにより、アクセスを提供できます。In cases where a nested type needs access to the instance members of its containing type, access can be provided by providing the this for the instance of the containing type as a constructor argument for the nested type. 次の例では、The following example

using System;

class C
{
    int i = 123;

    public void F() {
        Nested n = new Nested(this);
        n.G();
    }

    public class Nested
    {
        C this_c;

        public Nested(C c) {
            this_c = c;
        }

        public void G() {
            Console.WriteLine(this_c.i);
        }
    }
}

class Test
{
    static void Main() {
        C c = new C();
        c.F();
    }
}

この手法を示します。shows this technique. C のインスタンスは Nested のインスタンスを作成し、その独自の thisNestedのコンストラクターに渡して、後続の Cのインスタンスメンバーへのアクセスを提供します。An instance of C creates an instance of Nested and passes its own this to Nested's constructor in order to provide subsequent access to C's instance members.

包含する型のプライベートメンバーとプロテクトメンバーへのアクセスAccess to private and protected members of the containing type

入れ子になった型は、含まれている型にアクセスできるすべてのメンバーにアクセスできます。これには、private があり、protected 宣言されたアクセシビリティを含む型のメンバーも含まれます。A nested type has access to all of the members that are accessible to its containing type, including members of the containing type that have private and protected declared accessibility. The example

using System;

class C 
{
    private static void F() {
        Console.WriteLine("C.F");
    }

    public class Nested 
    {
        public static void G() {
            F();
        }
    }
}

class Test 
{
    static void Main() {
        C.Nested.G();
    }
}

入れ子になったクラス Nestedを含む C クラスを表示します。shows a class C that contains a nested class Nested. Nested内では、メソッドは Cで定義されている F 静的メソッドを呼び出し G、プライベートで宣言されたアクセシビリティを F します。Within Nested, the method G calls the static method F defined in C, and F has private declared accessibility.

入れ子になった型は、それを含んでいる型の基本型で定義されているプロテクトメンバーにもアクセスできます。A nested type also may access protected members defined in a base type of its containing type. この例では、In the example

using System;

class Base 
{
    protected void F() {
        Console.WriteLine("Base.F");
    }
}

class Derived: Base 
{
    public class Nested 
    {
        public void G() {
            Derived d = new Derived();
            d.F();        // ok
        }
    }
}

class Test 
{
    static void Main() {
        Derived.Nested n = new Derived.Nested();
        n.G();
    }
}

入れ子になったクラスは、Derivedのインスタンスを介してを呼び出すことによって、Derivedの基本 Baseクラスで定義されている保護されたメソッド F Derived.Nested アクセスします。the nested class Derived.Nested accesses the protected method F defined in Derived's base class, Base, by calling through an instance of Derived.

ジェネリッククラスの入れ子にされた型Nested types in generic classes

ジェネリッククラスの宣言には、入れ子にされた型宣言を含めることができます。A generic class declaration can contain nested type declarations. 外側のクラスの型パラメーターは、入れ子にされた型内で使用できます。The type parameters of the enclosing class can be used within the nested types. 入れ子になった型宣言には、入れ子になった型にのみ適用される追加の型パラメーターを含めることができます。A nested type declaration can contain additional type parameters that apply only to the nested type.

ジェネリッククラスの宣言内に含まれるすべての型宣言は、暗黙的にジェネリック型宣言になります。Every type declaration contained within a generic class declaration is implicitly a generic type declaration. ジェネリック型内で入れ子にされた型への参照を書き込む場合は、その型引数を含む構築型の型に名前を付ける必要があります。When writing a reference to a type nested within a generic type, the containing constructed type, including its type arguments, must be named. ただし、外側のクラス内では、入れ子にされた型は修飾なしで使用できます。外側のクラスのインスタンスの型は、入れ子にされた型を構築するときに暗黙的に使用できます。However, from within the outer class, the nested type can be used without qualification; the instance type of the outer class can be implicitly used when constructing the nested type. 次の例は、Innerから作成された構築済みの型を参照するための3つの異なる正しい方法を示しています。最初の2つは同等です。The following example shows three different correct ways to refer to a constructed type created from Inner; the first two are equivalent:

class Outer<T>
{
    class Inner<U>
    {
        public static void F(T t, U u) {...}
    }

    static void F(T t) {
        Outer<T>.Inner<string>.F(t, "abc");      // These two statements have
        Inner<string>.F(t, "abc");               // the same effect

        Outer<int>.Inner<string>.F(3, "abc");    // This type is different

        Outer.Inner<string>.F(t, "abc");         // Error, Outer needs type arg
    }
}

無効なプログラミングスタイルですが、入れ子にされた型の型パラメーターは、外側の型で宣言されたメンバーまたは型パラメーターを隠ぺいすることができます。Although it is bad programming style, a type parameter in a nested type can hide a member or type parameter declared in the outer type:

class Outer<T>
{
    class Inner<T>        // Valid, hides Outer's T
    {
        public T t;       // Refers to Inner's T
    }
}

予約されたメンバー名Reserved member names

基になるC#ランタイム実装を容易にするために、プロパティ、イベント、またはインデクサーであるソースメンバーの宣言ごとに、実装は、メンバー宣言の種類、名前、および型に基づいて、2つのメソッドシグネチャを予約する必要があります。To facilitate the underlying C# run-time implementation, for each source member declaration that is a property, event, or indexer, the implementation must reserve two method signatures based on the kind of the member declaration, its name, and its type. 基になるランタイム実装でこれらの予約が使用されていない場合でも、シグネチャがこれらの予約済み署名のいずれかに一致するメンバーを宣言するプログラムでは、コンパイル時エラーになります。It is a compile-time error for a program to declare a member whose signature matches one of these reserved signatures, even if the underlying run-time implementation does not make use of these reservations.

予約された名前は宣言を導入しないため、メンバーの検索には関与しません。The reserved names do not introduce declarations, thus they do not participate in member lookup. ただし、宣言に関連付けられた予約済みメソッドシグネチャは継承 (継承) に参加し、new 修飾子 (新しい修飾子) で非表示にすることができます。However, a declaration's associated reserved method signatures do participate in inheritance (Inheritance), and can be hidden with the new modifier (The new modifier).

これらの名前の予約は、次の3つの目的で機能します。The reservation of these names serves three purposes:

  • 基になる実装が、 C#言語機能への get または set アクセスのために、通常の識別子をメソッド名として使用できるようにする場合は。To allow the underlying implementation to use an ordinary identifier as a method name for get or set access to the C# language feature.
  • C#言語機能へのアクセスを取得または設定するためのメソッド名として、他の言語が通常の識別子を使用して相互運用できるようにする場合は。To allow other languages to interoperate using an ordinary identifier as a method name for get or set access to the C# language feature.
  • 1つの準拠コンパイラによって受け入れられるソースが、すべてC#の実装で一貫して予約されたメンバー名の詳細を持つようにするために、別のコンパイラによって受け入れられるようにします。To help ensure that the source accepted by one conforming compiler is accepted by another, by making the specifics of reserved member names consistent across all C# implementations.

デストラクター (デストラクター) の宣言によって、シグネチャも予約されます (デストラクター用に予約されたメンバー名)。The declaration of a destructor (Destructors) also causes a signature to be reserved (Member names reserved for destructors).

プロパティ用に予約されたメンバー名Member names reserved for properties

T型のプロパティ P (プロパティ) の場合、次のシグネチャが予約されています。For a property P (Properties) of type T, the following signatures are reserved:

T get_P();
void set_P(T value);

どちらの署名も、プロパティが読み取り専用または書き込み専用であっても予約されています。Both signatures are reserved, even if the property is read-only or write-only.

この例では、In the example

using System;

class A
{
    public int P {
        get { return 123; }
    }
}

class B: A
{
    new public int get_P() {
        return 456;
    }

    new public void set_P(int value) {
    }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        Console.WriteLine(a.P);
        Console.WriteLine(b.P);
        Console.WriteLine(b.get_P());
    }
}

読み取り専用プロパティ Pを定義し、get_P および set_P メソッドの署名を予約 A クラス。a class A defines a read-only property P, thus reserving signatures for get_P and set_P methods. クラス B A から派生し、これらの予約済み署名の両方を非表示にします。A class B derives from A and hides both of these reserved signatures. この例では、次の出力が生成されます。The example produces the output:

123
123
456

イベント用に予約されたメンバー名Member names reserved for events

デリゲート型E のイベント(イベント)の場合、次のシグネチャが予約されていTます。For an event E (Events) of delegate type T, the following signatures are reserved:

void add_E(T handler);
void remove_E(T handler);

インデクサーに予約されたメンバー名Member names reserved for indexers

パラメーターリスト を持つ型のインデクサー(インデクサーT)の場合、次のシグネチャが予約されていLます。For an indexer (Indexers) of type T with parameter-list L, the following signatures are reserved:

T get_Item(L);
void set_Item(L, T value);

インデクサーが読み取り専用または書き込み専用の場合でも、両方の署名が予約されます。Both signatures are reserved, even if the indexer is read-only or write-only.

さらに、メンバー名 Item は予約されています。Furthermore the member name Item is reserved.

デストラクター用に予約されたメンバー名Member names reserved for destructors

デストラクター (デストラクター) を含むクラスでは、次のシグネチャが予約されています。For a class containing a destructor (Destructors), the following signature is reserved:

void Finalize();

定数Constants

定数は、定数値を表すクラスメンバーです。この値は、コンパイル時に計算できます。A constant is a class member that represents a constant value: a value that can be computed at compile-time. Constant_declarationは、指定された型の1つ以上の定数を導入します。A constant_declaration introduces one or more constants of a given type.

constant_declaration
    : attributes? constant_modifier* 'const' type constant_declarators ';'
    ;

constant_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    ;

constant_declarators
    : constant_declarator (',' constant_declarator)*
    ;

constant_declarator
    : identifier '=' constant_expression
    ;

Constant_declarationには、一連の属性(属性)、new 修飾子 (新しい修飾子)、および4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせを含めることができます。A constant_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), and a valid combination of the four access modifiers (Access modifiers). 属性と修飾子は、 constant_declarationによって宣言されたすべてのメンバーに適用されます。The attributes and modifiers apply to all of the members declared by the constant_declaration. 定数は静的メンバーと見なされますが、 constant_declarationでは、static 修飾子を必要とすることも許可することもありません。Even though constants are considered static members, a constant_declaration neither requires nor allows a static modifier. 同じ修飾子が定数宣言で複数回出現する場合、エラーになります。It is an error for the same modifier to appear multiple times in a constant declaration.

Constant_declarationは、宣言によって導入されるメンバーの型を指定します。The type of a constant_declaration specifies the type of the members introduced by the declaration. 型にはconstant_declaratorのリストが続き、それぞれに新しいメンバーが導入されています。The type is followed by a list of constant_declarators, each of which introduces a new member. Constant_declaratorは、メンバーに名前を付け、その後に "=" トークンを続け、その後にメンバーの値を指定するconstant_expression (定数式) で構成されます。A constant_declarator consists of an identifier that names the member, followed by an "=" token, followed by a constant_expression (Constant expressions) that gives the value of the member.

定数宣言で指定されるは、sbytebyteshortushortintuintlongulongcharfloatdoubledecimal、または boolである必要があります。 stringThe type specified in a constant declaration must be sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, string, an enum_type, or a reference_type. constant_expressionは、暗黙的な変換 (暗黙的な変換) によって対象の型に変換できる、ターゲット型または型の値を生成する必要があります。Each constant_expression must yield a value of the target type or of a type that can be converted to the target type by an implicit conversion (Implicit conversions).

定数のは、少なくとも定数自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The type of a constant must be at least as accessible as the constant itself (Accessibility constraints).

定数の値は、 simple_name (簡易名) またはmember_access (メンバーアクセス) を使用して式で取得されます。The value of a constant is obtained in an expression using a simple_name (Simple names) or a member_access (Member access).

定数は、 constant_expressionに参加させることができます。A constant can itself participate in a constant_expression. したがって、定数は、 constant_expressionを必要とするすべてのコンストラクトで使用できます。Thus, a constant may be used in any construct that requires a constant_expression. このような構成体の例としては、case ラベル、goto case ステートメント、enum メンバー宣言、属性、その他の定数宣言などがあります。Examples of such constructs include case labels, goto case statements, enum member declarations, attributes, and other constant declarations.

定数式」で説明されているように、 constant_expressionは、コンパイル時に完全に評価できる式です。As described in Constant expressions, a constant_expression is an expression that can be fully evaluated at compile-time. string 以外のreference_typeの null 以外の値を作成する唯一の方法は、new 演算子を適用することです。また、new 演算子はconstant_expressionでは許可されていないため、reference_type 以外の string の定数で使用できる値は nullだけです。Since the only way to create a non-null value of a reference_type other than string is to apply the new operator, and since the new operator is not permitted in a constant_expression, the only possible value for constants of reference_types other than string is null.

定数値のシンボリック名が必要であるが、その値の型が定数宣言で許可されていない場合、またはコンパイル時にconstant_expressionによって値を計算できない場合は、代わりに readonly フィールド (Readonly フィールド) を使用できます。When a symbolic name for a constant value is desired, but when the type of that value is not permitted in a constant declaration, or when the value cannot be computed at compile-time by a constant_expression, a readonly field (Readonly fields) may be used instead.

複数の定数を宣言する定数宣言は、同じ属性、修飾子、および型を持つ単一の定数の複数の宣言と同じです。A constant declaration that declares multiple constants is equivalent to multiple declarations of single constants with the same attributes, modifiers, and type. 次に例を示します。For example

class A
{
    public const double X = 1.0, Y = 2.0, Z = 3.0;
}

上記の式は、次の式と同じです。is equivalent to

class A
{
    public const double X = 1.0;
    public const double Y = 2.0;
    public const double Z = 3.0;
}

依存関係が循環的な性質を持たない限り、定数は同じプログラム内の他の定数に依存することができます。Constants are permitted to depend on other constants within the same program as long as the dependencies are not of a circular nature. コンパイラは、定数宣言を適切な順序で評価するように自動的に配置します。The compiler automatically arranges to evaluate the constant declarations in the appropriate order. この例では、In the example

class A
{
    public const int X = B.Z + 1;
    public const int Y = 10;
}

class B
{
    public const int Z = A.Y + 1;
}

コンパイラは最初に A.Yを評価した後、B.Zを評価し、最後に A.Xを評価して、1011、および 12の値を生成します。the compiler first evaluates A.Y, then evaluates B.Z, and finally evaluates A.X, producing the values 10, 11, and 12. 定数宣言は、他のプログラムの定数に依存する場合がありますが、このような依存関係は一方向でしか使用できません。Constant declarations may depend on constants from other programs, but such dependencies are only possible in one direction. 上記の例を参照して AB が個別のプログラムで宣言されている場合は、A.XB.Zに依存していても、B.Z に同時に依存していない可能性があります。A.YReferring to the example above, if A and B were declared in separate programs, it would be possible for A.X to depend on B.Z, but B.Z could then not simultaneously depend on A.Y.

フィールドFields

フィールドは、オブジェクトまたはクラスに関連付けられた変数を表すメンバーです。A field is a member that represents a variable associated with an object or class. Field_declarationには、指定された型の1つ以上のフィールドが導入されています。A field_declaration introduces one or more fields of a given type.

field_declaration
    : attributes? field_modifier* type variable_declarators ';'
    ;

field_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'readonly'
    | 'volatile'
    | field_modifier_unsafe
    ;

variable_declarators
    : variable_declarator (',' variable_declarator)*
    ;

variable_declarator
    : identifier ('=' variable_initializer)?
    ;

variable_initializer
    : expression
    | array_initializer
    ;

Field_declarationには、一連の属性(属性)、new 修飾子 (新しい修飾子)、4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせ、および static 修飾子 (静的およびインスタンスフィールド) を含めることができます。A field_declaration may include a set of attributes (Attributes), a new modifier (The new modifier), a valid combination of the four access modifiers (Access modifiers), and a static modifier (Static and instance fields). また、 field_declarationには、readonly 修飾子 (Readonly フィールド) または volatile 修飾子 (Volatile フィールド) を含めることができますが、両方を含めることはできません。In addition, a field_declaration may include a readonly modifier (Readonly fields) or a volatile modifier (Volatile fields) but not both. 属性と修飾子は、 field_declarationによって宣言されたすべてのメンバーに適用されます。The attributes and modifiers apply to all of the members declared by the field_declaration. 同じ修飾子がフィールド宣言に複数回出現する場合、エラーになります。It is an error for the same modifier to appear multiple times in a field declaration.

Field_declarationは、宣言によって導入されるメンバーの型を指定します。The type of a field_declaration specifies the type of the members introduced by the declaration. 型にはvariable_declaratorのリストが続き、それぞれに新しいメンバーが導入されています。The type is followed by a list of variable_declarators, each of which introduces a new member. Variable_declaratorは、そのメンバーに名前を付け、その後に "=" トークンと、そのメンバーの初期値を指定するvariable_initializer (変数初期化子) を指定する識別子で構成されます。A variable_declarator consists of an identifier that names that member, optionally followed by an "=" token and a variable_initializer (Variable initializers) that gives the initial value of that member.

フィールドのは、少なくともフィールド自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The type of a field must be at least as accessible as the field itself (Accessibility constraints).

フィールドの値は、 simple_name (簡易名) またはmember_access (メンバーアクセス) を使用して式で取得されます。The value of a field is obtained in an expression using a simple_name (Simple names) or a member_access (Member access). 非読み取り専用フィールドの値は、代入演算子 (代入演算子) を使用して変更されます。The value of a non-readonly field is modified using an assignment (Assignment operators). 非 readonly フィールドの値は、後置インクリメント演算子とデクリメント演算子 (後置インクリメント演算子およびデクリメント演算子) と前置インクリメント演算子 (前置インクリメント演算子および前置デクリメント演算子) を使用して取得および変更できます。The value of a non-readonly field can be both obtained and modified using postfix increment and decrement operators (Postfix increment and decrement operators) and prefix increment and decrement operators (Prefix increment and decrement operators).

複数のフィールドを宣言するフィールド宣言は、同じ属性、修飾子、および型を持つ1つのフィールドの複数の宣言と同じです。A field declaration that declares multiple fields is equivalent to multiple declarations of single fields with the same attributes, modifiers, and type. 次に例を示します。For example

class A
{
    public static int X = 1, Y, Z = 100;
}

上記の式は、次の式と同じです。is equivalent to

class A
{
    public static int X = 1;
    public static int Y;
    public static int Z = 100;
}

静的フィールドとインスタンスフィールドStatic and instance fields

フィールド宣言に static 修飾子が含まれている場合、宣言によって導入されるフィールドは静的フィールドです。When a field declaration includes a static modifier, the fields introduced by the declaration are static fields. static 修飾子が存在しない場合、宣言によって導入されるフィールドはインスタンスフィールドになります。When no static modifier is present, the fields introduced by the declaration are instance fields. C#静的フィールドおよびインスタンスフィールドは、によってサポートされるいくつかの種類の変数 (変数) のうち、それぞれ静的変数インスタンス変数として参照される場合があります。Static fields and instance fields are two of the several kinds of variables (Variables) supported by C#, and at times they are referred to as static variables and instance variables, respectively.

静的フィールドは、特定のインスタンスの一部ではありません。代わりに、閉じられた型のすべてのインスタンス間で共有されます (オープン型およびクローズ型)。A static field is not part of a specific instance; instead, it is shared amongst all instances of a closed type (Open and closed types). クローズされたクラス型のインスタンスの数に関係なく、関連付けられているアプリケーションドメインの静的フィールドのコピーは1つしかありません。No matter how many instances of a closed class type are created, there is only ever one copy of a static field for the associated application domain.

例 :For example:

class C<V>
{
    static int count = 0;

    public C() {
        count++;
    }

    public static int Count {
        get { return count; }
    }
}

class Application
{
    static void Main() {
        C<int> x1 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<double> x2 = new C<double>();
        Console.WriteLine(C<int>.Count);        // Prints 1

        C<int> x3 = new C<int>();
        Console.WriteLine(C<int>.Count);        // Prints 2
    }
}

インスタンスフィールドはインスタンスに属します。An instance field belongs to an instance. 具体的には、クラスのすべてのインスタンスには、そのクラスのすべてのインスタンスフィールドのセットが個別に含まれています。Specifically, every instance of a class contains a separate set of all the instance fields of that class.

フィールドが E.Mフォームのmember_access (メンバーアクセス) で参照されている場合、M が静的フィールドである場合、EMを含む型を表している必要があります。また、M がインスタンスフィールドの場合、E は Mを含む型のインスタンスを示す必要があります。When a field is referenced in a member_access (Member access) of the form E.M, if M is a static field, E must denote a type containing M, and if M is an instance field, E must denote an instance of a type containing M.

静的メンバーとインスタンスメンバーの違いについては、「静的メンバーとインスタンスメンバー」で詳しく説明します。The differences between static and instance members are discussed further in Static and instance members.

読み取り専用フィールドReadonly fields

Field_declarationreadonly 修飾子が含まれている場合、宣言によって導入されるフィールドは読み取り専用フィールドです。When a field_declaration includes a readonly modifier, the fields introduced by the declaration are readonly fields. 読み取り専用フィールドへの直接割り当ては、その宣言の一部として、または同じクラスのインスタンスコンストラクターまたは静的コンストラクターでのみ発生します。Direct assignments to readonly fields can only occur as part of that declaration or in an instance constructor or static constructor in the same class. (読み取り専用フィールドは、これらのコンテキストで複数回割り当てることができます)。具体的には、readonly フィールドへの直接割り当ては、次のコンテキストでのみ許可されます。(A readonly field can be assigned to multiple times in these contexts.) Specifically, direct assignments to a readonly field are permitted only in the following contexts:

  • (宣言にvariable_initializerを含めることによって) フィールドが導入されているvariable_declaratorIn the variable_declarator that introduces the field (by including a variable_initializer in the declaration).
  • インスタンスフィールドの場合、フィールド宣言を含むクラスのインスタンスコンストラクター。静的フィールドの場合は、フィールド宣言を含むクラスの静的コンストラクター。For an instance field, in the instance constructors of the class that contains the field declaration; for a static field, in the static constructor of the class that contains the field declaration. これらは、readonly フィールドを out または ref パラメーターとして渡すことができる唯一のコンテキストでもあります。These are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.

readonly フィールドに割り当てたり、他のコンテキストで out または ref パラメーターとして渡したりしようとすると、コンパイル時エラーになります。Attempting to assign to a readonly field or pass it as an out or ref parameter in any other context is a compile-time error.

静的読み取り専用フィールドを定数に使用するUsing static readonly fields for constants

static readonly フィールドは、定数値のシンボル名が必要なときに、値の型が const 宣言で許可されていない場合、またはコンパイル時に値を計算できない場合に便利です。A static readonly field is useful when a symbolic name for a constant value is desired, but when the type of the value is not permitted in a const declaration, or when the value cannot be computed at compile-time. この例では、In the example

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);

    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

BlackWhiteRedGreen、および Blue のメンバーは、コンパイル時に値を計算できないため、const メンバーとして宣言することはできません。the Black, White, Red, Green, and Blue members cannot be declared as const members because their values cannot be computed at compile-time. ただし、これらの static readonly 宣言することは、ほとんど同じ効果を持ちます。However, declaring them static readonly instead has much the same effect.

定数と静的な読み取り専用フィールドのバージョン管理Versioning of constants and static readonly fields

定数および読み取り専用フィールドには、異なるバイナリバージョン管理セマンティクスがあります。Constants and readonly fields have different binary versioning semantics. 式が定数を参照する場合、定数の値はコンパイル時に取得されますが、式が読み取り専用フィールドを参照する場合、フィールドの値は実行時まで取得されません。When an expression references a constant, the value of the constant is obtained at compile-time, but when an expression references a readonly field, the value of the field is not obtained until run-time. 2つの独立したプログラムで構成されるアプリケーションを考えてみましょう。Consider an application that consists of two separate programs:

using System;

namespace Program1
{
    public class Utils
    {
        public static readonly int X = 1;
    }
}

namespace Program2
{
    class Test
    {
        static void Main() {
            Console.WriteLine(Program1.Utils.X);
        }
    }
}

Program1Program2 の名前空間は、個別にコンパイルされる2つのプログラムを表します。The Program1 and Program2 namespaces denote two programs that are compiled separately. Program1.Utils.X が静的な読み取り専用フィールドとして宣言されているため、Console.WriteLine ステートメントによって出力される値はコンパイル時には認識されませんが、実行時に取得されます。Because Program1.Utils.X is declared as a static readonly field, the value output by the Console.WriteLine statement is not known at compile-time, but rather is obtained at run-time. したがって、X の値が変更され Program1 が再コンパイルされた場合、Program2 が再コンパイルされない場合でも、Console.WriteLine ステートメントによって新しい値が出力されます。Thus, if the value of X is changed and Program1 is recompiled, the Console.WriteLine statement will output the new value even if Program2 isn't recompiled. ただし、X が定数であった場合、X の値は Program2 のコンパイル時に取得され、Program2 が再コンパイルされるまで Program1 の変更による影響を受けません。However, had X been a constant, the value of X would have been obtained at the time Program2 was compiled, and would remain unaffected by changes in Program1 until Program2 is recompiled.

Volatile フィールドVolatile fields

Field_declarationvolatile 修飾子が含まれている場合、その宣言によって導入されるフィールドはvolatile フィールドです。When a field_declaration includes a volatile modifier, the fields introduced by that declaration are volatile fields.

非 volatile フィールドの場合、命令の順序を変更する最適化手法は、予期しない、予測できない結果になる可能性があります。これは、 lock_statement (lock ステートメント) によって提供されるような同期を行わずにフィールドにアクセスするマルチスレッドプログラムです。For non-volatile fields, optimization techniques that reorder instructions can lead to unexpected and unpredictable results in multi-threaded programs that access fields without synchronization such as that provided by the lock_statement (The lock statement). これらの最適化は、コンパイラ、ランタイムシステム、またはハードウェアによって実行できます。These optimizations can be performed by the compiler, by the run-time system, or by hardware. Volatile フィールドの場合、このような並べ替えの最適化は制限されます。For volatile fields, such reordering optimizations are restricted:

  • Volatile フィールドの読み取りは、 volatile 読み取りと呼ばれます。A read of a volatile field is called a volatile read. 揮発性読み取りには "取得セマンティクス" があります。つまり、命令シーケンス内で発生したメモリへの参照の前に発生することが保証されます。A volatile read has "acquire semantics"; that is, it is guaranteed to occur prior to any references to memory that occur after it in the instruction sequence.
  • Volatile フィールドの書き込みは、 volatile 書き込みと呼ばれます。A write of a volatile field is called a volatile write. Volatile 書き込みには "リリースセマンティクス" があります。つまり、命令シーケンスで書き込み命令より前のメモリ参照の後に発生することは保証されます。A volatile write has "release semantics"; that is, it is guaranteed to happen after any memory references prior to the write instruction in the instruction sequence.

これらの制限により、すべてのスレッドが、他のスレッドによって実行された volatile の書き込みを、実行された順序で観察することが保証されます。These restrictions ensure that all threads will observe volatile writes performed by any other thread in the order in which they were performed. すべての実行スレッドから見たように、volatile 書き込みの単一の合計順序を指定するために、準拠している実装は必要ありません。A conforming implementation is not required to provide a single total ordering of volatile writes as seen from all threads of execution. Volatile フィールドの型は、次のいずれかである必要があります。The type of a volatile field must be one of the following:

  • Reference_typeA reference_type.
  • bytesbyteshortushortintuintcharfloatboolSystem.IntPtr、または System.UIntPtrThe type byte, sbyte, short, ushort, int, uint, char, float, bool, System.IntPtr, or System.UIntPtr.
  • bytesbyteshortushortint、または uintの enum 基本型を持つenum_typeAn enum_type having an enum base type of byte, sbyte, short, ushort, int, or uint.

The example

using System;
using System.Threading;

class Test
{
    public static int result;   
    public static volatile bool finished;

    static void Thread2() {
        result = 143;    
        finished = true; 
    }

    static void Main() {
        finished = false;

        // Run Thread2() in a new thread
        new Thread(new ThreadStart(Thread2)).Start();

        // Wait for Thread2 to signal that it has a result by setting
        // finished to true.
        for (;;) {
            if (finished) {
                Console.WriteLine("result = {0}", result);
                return;
            }
        }
    }
}

この例では、次のように出力されます。produces the output:

result = 143

この例では、メソッド Main Thread2メソッドを実行する新しいスレッドを開始します。In this example, the method Main starts a new thread that runs the method Thread2. このメソッドは、値を resultという非 volatile フィールドに格納し、true を volatile フィールド finishedに格納します。This method stores a value into a non-volatile field called result, then stores true in the volatile field finished. メインスレッドは、フィールド finishedtrueに設定されるのを待機し、resultフィールドを読み取ります。The main thread waits for the field finished to be set to true, then reads the field result. finishedvolatileとして宣言されているため、メインスレッドは、フィールド resultから 143 値を読み取る必要があります。Since finished has been declared volatile, the main thread must read the value 143 from the field result. フィールド finishedvolatile``result として宣言されていない場合、ストアが finishedする前にメインスレッドに表示されるようにすることができます。したがって、メインスレッドは 0 フィールドからの値を読み取ることができます。resultIf the field finished had not been declared volatile, then it would be permissible for the store to result to be visible to the main thread after the store to finished, and hence for the main thread to read the value 0 from the field result. finishedvolatile フィールドとして宣言すると、そのような不整合を防ぐことができます。Declaring finished as a volatile field prevents any such inconsistency.

フィールドの初期化Field initialization

フィールドの初期値は、静的フィールドであるか、インスタンスフィールドであるかにかかわらず、フィールドの型の既定値 (既定値) になります。The initial value of a field, whether it be a static field or an instance field, is the default value (Default values) of the field's type. この既定の初期化が発生する前にフィールドの値を確認することはできず、フィールドは "初期化されていません" にはなりません。It is not possible to observe the value of a field before this default initialization has occurred, and a field is thus never "uninitialized". The example

using System;

class Test
{
    static bool b;
    int i;

    static void Main() {
        Test t = new Test();
        Console.WriteLine("b = {0}, i = {1}", b, t.i);
    }
}

この例では、次のように出力されます。produces the output

b = False, i = 0

bi は両方とも既定値に自動的に初期化されるためです。because b and i are both automatically initialized to default values.

変数初期化子Variable initializers

フィールド宣言にはvariable_initializers を含めることができます。Field declarations may include variable_initializers. 静的フィールドの場合、変数初期化子は、クラスの初期化中に実行される代入ステートメントに対応します。For static fields, variable initializers correspond to assignment statements that are executed during class initialization. インスタンスフィールドの場合、変数初期化子は、クラスのインスタンスが作成されるときに実行される代入ステートメントに対応します。For instance fields, variable initializers correspond to assignment statements that are executed when an instance of the class is created.

The example

using System;

class Test
{
    static double x = Math.Sqrt(2.0);
    int i = 100;
    string s = "Hello";

    static void Main() {
        Test a = new Test();
        Console.WriteLine("x = {0}, i = {1}, s = {2}", x, a.i, a.s);
    }
}

この例では、次のように出力されます。produces the output

x = 1.4142135623731, i = 100, s = Hello

x への代入は、静的フィールド初期化子が実行され、i に割り当てられ、インスタンスフィールド初期化子の実行時に s 発生する場合に発生します。because an assignment to x occurs when static field initializers execute and assignments to i and s occur when the instance field initializers execute.

フィールドの初期化」で説明されている既定値の初期化は、変数初期化子を持つフィールドを含むすべてのフィールドに対して行われます。The default value initialization described in Field initialization occurs for all fields, including fields that have variable initializers. したがって、クラスが初期化されると、そのクラスのすべての静的フィールドが最初に既定値に初期化され、次に静的フィールド初期化子がテキスト順に実行されます。Thus, when a class is initialized, all static fields in that class are first initialized to their default values, and then the static field initializers are executed in textual order. 同様に、クラスのインスタンスが作成されると、そのインスタンス内のすべてのインスタンスフィールドが最初に既定値に初期化され、次に、インスタンスフィールド初期化子がテキスト順に実行されます。Likewise, when an instance of a class is created, all instance fields in that instance are first initialized to their default values, and then the instance field initializers are executed in textual order.

変数初期化子を持つ静的フィールドを既定値の状態で観察することができます。It is possible for static fields with variable initializers to be observed in their default value state. ただし、スタイルの問題としては、この方法は推奨されません。However, this is strongly discouraged as a matter of style. The example

using System;

class Test
{
    static int a = b + 1;
    static int b = a + 1;

    static void Main() {
        Console.WriteLine("a = {0}, b = {1}", a, b);
    }
}

この動作を行います。exhibits this behavior. A と b の循環定義にかかわらず、プログラムは有効です。Despite the circular definitions of a and b, the program is valid. 結果が出力されます。It results in the output

a = 1, b = 2

静的フィールド ab は、初期化子が実行される前に 0 (intの既定値) に初期化されるためです。because the static fields a and b are initialized to 0 (the default value for int) before their initializers are executed. a の初期化子が実行されると、b の値が0になり、a1に初期化されます。When the initializer for a runs, the value of b is zero, and so a is initialized to 1. b の初期化子を実行すると、a の値は既に 1ため、b2に初期化されます。When the initializer for b runs, the value of a is already 1, and so b is initialized to 2.

静的フィールドの初期化Static field initialization

クラスの静的フィールド変数初期化子は、クラス宣言に出現するテキスト順に実行される割り当てのシーケンスに対応します。The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. 静的コンストラクター (静的コンストラクター) がクラスに存在する場合、静的コンストラクターを実行する直前に静的フィールド初期化子が実行されます。If a static constructor (Static constructors) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. それ以外の場合、静的フィールド初期化子は、そのクラスの静的フィールドを最初に使用する前に、実装に依存する時刻に実行されます。Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class. The example

using System;

class Test 
{ 
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    public static int X = Test.F("Init A");
}

class B
{
    public static int Y = Test.F("Init B");
}

では、次の出力が生成される場合があります。might produce either the output:

Init A
Init B
1 1

または、次のように出力します。or the output:

Init B
Init A
1 1

Xの初期化子と Yの初期化子の実行は、どちらの順序でも発生する可能性があります。これらのフィールドへの参照の前にのみ発生するように制限されています。because the execution of X's initializer and Y's initializer could occur in either order; they are only constrained to occur before the references to those fields. ただし、この例では次のようになります。However, in the example:

using System;

class Test
{
    static void Main() {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s) {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    static A() {}

    public static int X = Test.F("Init A");
}

class B
{
    static B() {}

    public static int Y = Test.F("Init B");
}

出力は次のようになります。the output must be:

Init B
Init A
1 1

静的コンストラクターを実行するときの規則 (静的コンストラクターで定義されているように) は、Bの静的コンストラクター (したがって Bの静的フィールド初期化子) を Aの静的コンストラクターとフィールド初期化子の前に実行する必要があるためです。because the rules for when static constructors execute (as defined in Static constructors) provide that B's static constructor (and hence B's static field initializers) must run before A's static constructor and field initializers.

インスタンスフィールドの初期化Instance field initialization

クラスのインスタンスフィールド変数初期化子は、そのクラスのインスタンスコンストラクター (コンストラクター初期化子) のいずれかにエントリしたときに直ちに実行される割り当てのシーケンスに対応します。The instance field variable initializers of a class correspond to a sequence of assignments that are executed immediately upon entry to any one of the instance constructors (Constructor initializers) of that class. 変数初期化子は、クラス宣言に含まれるテキスト順に実行されます。The variable initializers are executed in the textual order in which they appear in the class declaration. クラスインスタンスの作成と初期化のプロセスについては、「インスタンスコンストラクター」を参照してください。The class instance creation and initialization process is described further in Instance constructors.

インスタンスフィールドの変数初期化子では、作成されるインスタンスを参照できません。A variable initializer for an instance field cannot reference the instance being created. このため、変数初期化子で this を参照するにはコンパイル時エラーが発生します。これは、変数初期化子がsimple_nameを通じて任意のインスタンスメンバーを参照するためのコンパイル時エラーであるためです。Thus, it is a compile-time error to reference this in a variable initializer, as it is a compile-time error for a variable initializer to reference any instance member through a simple_name. この例では、In the example

class A
{
    int x = 1;
    int y = x + 1;        // Error, reference to instance member of this
}

y の変数初期化子は、作成されるインスタンスのメンバーを参照するため、コンパイル時エラーになります。the variable initializer for y results in a compile-time error because it references a member of the instance being created.

メソッドMethods

"メソッド" は、オブジェクトまたはクラスによって実行可能な計算またはアクションを実装するメンバーです。A method is a member that implements a computation or action that can be performed by an object or class. メソッドはmethod_declarations を使用して宣言されます。Methods are declared using method_declarations:

method_declaration
    : method_header method_body
    ;

method_header
    : attributes? method_modifier* 'partial'? return_type member_name type_parameter_list?
      '(' formal_parameter_list? ')' type_parameter_constraints_clause*
    ;

method_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | 'async'
    | method_modifier_unsafe
    ;

return_type
    : type
    | 'void'
    ;

member_name
    : identifier
    | interface_type '.' identifier
    ;

method_body
    : block
    | '=>' expression ';'
    | ';'
    ;

Method_declarationには、属性(属性) のセットと、4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせ、new (新しい修飾子)、static (静的メソッドとインスタンスメソッド)、virtual (仮想メソッド)、override (オーバーライドメソッド)、(シールメソッド)、sealed (抽象メソッド)、および abstract (外部メソッド) 修飾子を含めることができます。externA method_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

次のすべての条件を満たす場合、宣言には修飾子の有効な組み合わせがあります。A declaration has a valid combination of modifiers if all of the following are true:

  • この宣言には、アクセス修飾子 (アクセス修飾子) の有効な組み合わせが含まれています。The declaration includes a valid combination of access modifiers (Access modifiers).
  • 宣言に、同じ修飾子が複数回含まれていません。The declaration does not include the same modifier multiple times.
  • 宣言には、staticvirtual、および overrideの修飾子が1つだけ含まれています。The declaration includes at most one of the following modifiers: static, virtual, and override.
  • 宣言には、newoverrideの修飾子が1つだけ含まれています。The declaration includes at most one of the following modifiers: new and override.
  • 宣言に abstract 修飾子が含まれている場合、宣言には、staticvirtualsealed または externの修飾子は含まれません。If the declaration includes the abstract modifier, then the declaration does not include any of the following modifiers: static, virtual, sealed or extern.
  • 宣言に private 修飾子が含まれている場合、宣言には、virtualoverride、または abstractの各修飾子は含まれません。If the declaration includes the private modifier, then the declaration does not include any of the following modifiers: virtual, override, or abstract.
  • 宣言に sealed 修飾子が含まれている場合、宣言には override 修飾子も含まれます。If the declaration includes the sealed modifier, then the declaration also includes the override modifier.
  • 宣言に partial 修飾子が含まれている場合は、newpublicprotectedinternalprivatevirtualsealedoverrideabstractexternの修飾子は含まれません。If the declaration includes the partial modifier, then it does not include any of the following modifiers: new, public, protected, internal, private, virtual, sealed, override, abstract, or extern.

async 修飾子を持つメソッドは、非同期関数であり、「 async 関数」で説明されている規則に従います。A method that has the async modifier is an async function and follows the rules described in Async functions.

メソッド宣言のreturn_typeは、計算され、メソッドによって返される値の型を指定します。The return_type of a method declaration specifies the type of the value computed and returned by the method. メソッドが値を返さない場合、 return_typevoid です。The return_type is void if the method does not return a value. 宣言に partial 修飾子が含まれている場合は、戻り値の型が voidである必要があります。If the declaration includes the partial modifier, then the return type must be void.

Member_nameは、メソッドの名前を指定します。The member_name specifies the name of the method. メソッドが明示的なインターフェイスメンバーの実装 (明示的なインターフェイスメンバーの実装) でない限り、 member_nameは単なる識別子です。Unless the method is an explicit interface member implementation (Explicit interface member implementations), the member_name is simply an identifier. 明示的なインターフェイスメンバーの実装では、 member_nameinterface_typeの後に "." と識別子が続きます。For an explicit interface member implementation, the member_name consists of an interface_type followed by a "." and an identifier.

省略可能なtype_parameter_listは、メソッド (型パラメーター) の型パラメーターを指定します。The optional type_parameter_list specifies the type parameters of the method (Type parameters). Type_parameter_listが指定されている場合、メソッドはジェネリックメソッドです。If a type_parameter_list is specified the method is a generic method. メソッドに extern 修飾子がある場合、 type_parameter_listを指定することはできません。If the method has an extern modifier, a type_parameter_list cannot be specified.

省略可能なformal_parameter_listは、メソッドのパラメーター (メソッドパラメーター) を指定します。The optional formal_parameter_list specifies the parameters of the method (Method parameters).

省略可能なtype_parameter_constraints_clauses では、個々の型パラメーター (型パラメーター制約) に対して制約を指定し、 type_parameter_listが指定されている場合にのみ指定できます。また、メソッドには override 修飾子がありません。The optional type_parameter_constraints_clauses specify constraints on individual type parameters (Type parameter constraints) and may only be specified if a type_parameter_list is also supplied, and the method does not have an override modifier.

メソッドのformal_parameter_listで参照されるreturn_typeと各型は、少なくともメソッド自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The return_type and each of the types referenced in the formal_parameter_list of a method must be at least as accessible as the method itself (Accessibility constraints).

Method_bodyは、セミコロン、ステートメント本体、または式の本体です。The method_body is either a semicolon, a statement body or an expression body. ステートメントの本体は、メソッドが呼び出されたときに実行するステートメントを指定するブロックで構成されます。A statement body consists of a block, which specifies the statements to execute when the method is invoked. 式の本体は、=> の後にとセミコロンが続く形式で構成され、メソッドが呼び出されたときに実行する1つの式を示します。An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the method is invoked.

abstract および extern メソッドの場合、 method_bodyは単にセミコロンで構成されます。For abstract and extern methods, the method_body consists simply of a semicolon. partial メソッドの場合、 method_bodyは、セミコロン、ブロック本体、または式の本体で構成されます。For partial methods the method_body may consist of either a semicolon, a block body or an expression body. その他のすべてのメソッドでは、 method_bodyはブロック本体または式本体のいずれかになります。For all other methods, the method_body is either a block body or an expression body.

Method_bodyがセミコロンで構成されている場合、宣言に async 修飾子が含まれていない可能性があります。If the method_body consists of a semicolon, then the declaration may not include the async modifier.

メソッドの名前、型パラメーターリスト、およびメソッドの仮パラメーターリストは、メソッドのシグネチャ (シグネチャとオーバーロード) を定義します。The name, the type parameter list and the formal parameter list of a method define the signature (Signatures and overloading) of the method. 具体的には、メソッドのシグネチャは、その名前、型パラメーターの数、およびその仮パラメーターの数、修飾子、および型で構成されます。Specifically, the signature of a method consists of its name, the number of type parameters and the number, modifiers, and types of its formal parameters. このため、仮パラメーターの型で発生するメソッドの型パラメーターは、その名前ではなく、メソッドの型引数リスト内の序数位置によって識別されます。戻り値の型は、メソッドのシグネチャの一部ではなく、型パラメーターまたは仮パラメーターの名前でもありません。For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type argument list of the method.The return type is not part of a method's signature, nor are the names of the type parameters or the formal parameters.

メソッドの名前は、同じクラスで宣言されている他のすべての非メソッドの名前と異なる必要があります。The name of a method must differ from the names of all other non-methods declared in the same class. さらに、メソッドのシグネチャは、同じクラス内で宣言されている他のすべてのメソッドのシグネチャとは異なる必要があります。また、同じクラスで宣言された2つのメソッドは、refoutだけが異なるシグネチャを持つことはできません。In addition, the signature of a method must differ from the signatures of all other methods declared in the same class, and two methods declared in the same class may not have signatures that differ solely by ref and out.

メソッドのtype_parametermethod_declaration全体を通じてスコープ内にあり、 return_typemethod_bodytype_parameter_constraints_clauses で、属性ではなく、そのスコープ全体の型を形成するために使用できます。The method's type_parameters are in scope throughout the method_declaration, and can be used to form types throughout that scope in return_type, method_body, and type_parameter_constraints_clauses but not in attributes.

すべての仮パラメーターと型パラメーターには、異なる名前を付ける必要があります。All formal parameters and type parameters must have different names.

メソッドパラメーターMethod parameters

メソッドのパラメーター (存在する場合) は、メソッドのformal_parameter_listによって宣言されます。The parameters of a method, if any, are declared by the method's formal_parameter_list.

formal_parameter_list
    : fixed_parameters
    | fixed_parameters ',' parameter_array
    | parameter_array
    ;

fixed_parameters
    : fixed_parameter (',' fixed_parameter)*
    ;

fixed_parameter
    : attributes? parameter_modifier? type identifier default_argument?
    ;

default_argument
    : '=' expression
    ;

parameter_modifier
    : 'ref'
    | 'out'
    | 'this'
    ;

parameter_array
    : attributes? 'params' array_type identifier
    ;

仮パラメーターリストは1つ以上のコンマ区切りのパラメーターで構成され、最後のパラメーターだけがparameter_arrayになる可能性があります。The formal parameter list consists of one or more comma-separated parameters of which only the last may be a parameter_array.

Fixed_parameterは、省略可能な属性のセット (属性)、省略可能な refout または this 修飾子、識別子、および省略可能なdefault_argumentで構成されます。A fixed_parameter consists of an optional set of attributes (Attributes), an optional ref, out or this modifier, a type, an identifier and an optional default_argument. fixed_parameterは、指定された名前を使用して、指定された型のパラメーターを宣言します。Each fixed_parameter declares a parameter of the given type with the given name. this 修飾子は、メソッドを拡張メソッドとして指定し、静的メソッドの最初のパラメーターでのみ使用できます。The this modifier designates the method as an extension method and is only allowed on the first parameter of a static method. 拡張メソッドの詳細については、「拡張メソッド」を参照してください。Extension methods are further described in Extension methods.

Default_argumentを持つfixed_parameter省略可能なパラメーターとして知られていますが、 default_argumentのないfixed_parameter必須パラメーターです。A fixed_parameter with a default_argument is known as an optional parameter, whereas a fixed_parameter without a default_argument is a required parameter. 必須パラメーターは、 formal_parameter_list内の省略可能なパラメーターの後に指定することはできません。A required parameter may not appear after an optional parameter in a formal_parameter_list.

ref または out パラメーターにdefault_argumentを指定することはできません。A ref or out parameter cannot have a default_argument. Default_argument内のは、次のいずれかである必要があります。The expression in a default_argument must be one of the following:

  • constant_expressiona constant_expression
  • S が値型である new S() フォームの式an expression of the form new S() where S is a value type
  • S が値型である default(S) フォームの式an expression of the form default(S) where S is a value type

は、id または null 許容型からパラメーターの型への変換によって、暗黙的に変換可能である必要があります。The expression must be implicitly convertible by an identity or nullable conversion to the type of the parameter.

部分メソッド宣言の実装 (部分メソッド)、明示的なインターフェイスメンバーの実装 (明示的なインターフェイスメンバーの実装)、または単一パラメーターインデクサー宣言 (インデクサー) で、省略可能なパラメーターが発生した場合、コンパイラは警告を出する必要があります。これらのメンバーは、引数を省略できるようには呼び出されないためです。If optional parameters occur in an implementing partial method declaration (Partial methods) , an explicit interface member implementation (Explicit interface member implementations) or in a single-parameter indexer declaration (Indexers) the compiler should give a warning, since these members can never be invoked in a way that permits arguments to be omitted.

Parameter_arrayは、省略可能な属性のセット (属性)、params 修飾子、 array_type、および識別子で構成されます。A parameter_array consists of an optional set of attributes (Attributes), a params modifier, an array_type, and an identifier. パラメーター配列は、指定された名前を持つ指定された配列型の1つのパラメーターを宣言します。A parameter array declares a single parameter of the given array type with the given name. パラメーター配列のarray_typeは、1次元配列型 (配列型) である必要があります。The array_type of a parameter array must be a single-dimensional array type (Array types). メソッド呼び出しでは、パラメーター配列は、指定された配列型の1つの引数を指定するか、配列要素型の0個以上の引数を指定できるようにします。In a method invocation, a parameter array permits either a single argument of the given array type to be specified, or it permits zero or more arguments of the array element type to be specified. パラメーター配列の詳細については、「パラメーター配列」を参照してください。Parameter arrays are described further in Parameter arrays.

Parameter_arrayは省略可能なパラメーターの後に発生することがありますが、既定値を持つことはできません。 parameter_arrayの引数を省略すると、代わりに空の配列が作成されます。A parameter_array may occur after an optional parameter, but cannot have a default value -- the omission of arguments for a parameter_array would instead result in the creation of an empty array.

次の例は、さまざまな種類のパラメーターを示しています。The following example illustrates different kinds of parameters:

public void M(
    ref int      i,
    decimal      d,
    bool         b = false,
    bool?        n = false,
    string       s = "Hello",
    object       o = null,
    T            t = default(T),
    params int[] a
) { }

Mformal_parameter_listでは、i は必須の ref パラメーターです。 d は必須の値パラメーター、bso であり、t はパラメーター配列です。aIn the formal_parameter_list for M, i is a required ref parameter, d is a required value parameter, b, s, o and t are optional value parameters and a is a parameter array.

メソッド宣言は、パラメーター、型パラメーター、およびローカル変数に対して個別の宣言領域を作成します。A method declaration creates a separate declaration space for parameters, type parameters and local variables. 名前は、型パラメーターリストとメソッドの仮パラメーターリスト、およびメソッドのブロック内のローカル変数宣言によって、この宣言領域に導入されます。Names are introduced into this declaration space by the type parameter list and the formal parameter list of the method and by local variable declarations in the block of the method. メソッド宣言空間の2つのメンバーが同じ名前を持つ場合、エラーになります。It is an error for two members of a method declaration space to have the same name. メソッド宣言領域と入れ子になった宣言空間のローカル変数宣言領域が同じ名前の要素を含む場合、エラーになります。It is an error for the method declaration space and the local variable declaration space of a nested declaration space to contain elements with the same name.

メソッドの呼び出し (メソッド呼び出し) によって、メソッドの仮パラメーターとローカル変数の、その呼び出しに固有のコピーが作成され、呼び出しの引数リストによって、新しく作成された仮パラメーターに値または変数参照が割り当てられます。A method invocation (Method invocations) creates a copy, specific to that invocation, of the formal parameters and local variables of the method, and the argument list of the invocation assigns values or variable references to the newly created formal parameters. メソッドのブロック内では、 Simple_name式 (簡易名) の識別子によって仮パラメーターを参照できます。Within the block of a method, formal parameters can be referenced by their identifiers in simple_name expressions (Simple names).

仮引数には4種類あります。There are four kinds of formal parameters:

  • 値パラメーター。修飾子なしで宣言されます。Value parameters, which are declared without any modifiers.
  • 参照パラメーター。 ref 修飾子を使用して宣言されます。Reference parameters, which are declared with the ref modifier.
  • 出力パラメーター。 out 修飾子を使用して宣言されます。Output parameters, which are declared with the out modifier.
  • パラメーター配列。 params 修飾子を使用して宣言されます。Parameter arrays, which are declared with the params modifier.

シグネチャとオーバーロード」で説明されているように、ref 修飾子と out 修飾子はメソッドのシグネチャの一部ですが、params 修飾子は含まれません。As described in Signatures and overloading, the ref and out modifiers are part of a method's signature, but the params modifier is not.

値パラメーターValue parameters

修飾子を指定せずに宣言されたパラメーターは、値パラメーターです。A parameter declared with no modifiers is a value parameter. 値パラメーターは、メソッドの呼び出しで指定された対応する引数から初期値を取得するローカル変数に対応します。A value parameter corresponds to a local variable that gets its initial value from the corresponding argument supplied in the method invocation.

仮パラメーターが値パラメーターの場合、メソッド呼び出しの対応する引数は、暗黙的に変換可能な (暗黙の型変換) 式である必要があります。When a formal parameter is a value parameter, the corresponding argument in a method invocation must be an expression that is implicitly convertible (Implicit conversions) to the formal parameter type.

メソッドは、値パラメーターに新しい値を割り当てることができます。A method is permitted to assign new values to a value parameter. このような割り当ては、値パラメーターによって表されるローカルストレージの場所にのみ影響します。メソッドの呼び出しで指定された実際の引数には影響しません。Such assignments only affect the local storage location represented by the value parameter—they have no effect on the actual argument given in the method invocation.

参照パラメーターReference parameters

ref 修飾子で宣言されたパラメーターは参照パラメーターです。A parameter declared with a ref modifier is a reference parameter. 値パラメーターとは異なり、参照パラメーターは新しいストレージの場所を作成しません。Unlike a value parameter, a reference parameter does not create a new storage location. 代わりに、参照パラメーターは、メソッド呼び出しで引数として指定された変数と同じ格納場所を表します。Instead, a reference parameter represents the same storage location as the variable given as the argument in the method invocation.

仮パラメーターが参照パラメーターである場合、メソッド呼び出しの対応する引数は、キーワード ref の後に、仮パラメーターと同じ型のvariable_reference (明確な代入を決定するための正確な規則) が含まれている必要があります。When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. 参照パラメーターとして渡すには、変数を確実に代入する必要があります。A variable must be definitely assigned before it can be passed as a reference parameter.

メソッド内では、参照パラメーターは常に確実に割り当てられていると見なされます。Within a method, a reference parameter is always considered definitely assigned.

反復子 (反復子) として宣言されたメソッドに参照パラメーターを含めることはできません。A method declared as an iterator (Iterators) cannot have reference parameters.

The example

using System;

class Test
{
    static void Swap(ref int x, ref int y) {
        int temp = x;
        x = y;
        y = temp;
    }

    static void Main() {
        int i = 1, j = 2;
        Swap(ref i, ref j);
        Console.WriteLine("i = {0}, j = {1}", i, j);
    }
}

この例では、次のように出力されます。produces the output

i = 2, j = 1

MainSwap を呼び出す場合、xi を表し、yjを表します。For the invocation of Swap in Main, x represents i and y represents j. このため、呼び出しは ijの値をスワップする効果を持ちます。Thus, the invocation has the effect of swapping the values of i and j.

参照パラメーターを受け取るメソッドでは、複数の名前が同じストレージの場所を表すことができます。In a method that takes reference parameters it is possible for multiple names to represent the same storage location. この例では、In the example

class A
{
    string s;

    void F(ref string a, ref string b) {
        s = "One";
        a = "Two";
        b = "Three";
    }

    void G() {
        F(ref s, ref s);
    }
}

GF を呼び出すと、abの両方に対して s への参照が渡されます。the invocation of F in G passes a reference to s for both a and b. そのため、この呼び出しでは、sa、および b の名前はすべて同じストレージの場所を参照し、3つの割り当てはすべて、インスタンスフィールド sを変更します。Thus, for that invocation, the names s, a, and b all refer to the same storage location, and the three assignments all modify the instance field s.

出力パラメーターOutput parameters

out 修飾子で宣言されたパラメーターは出力パラメーターです。A parameter declared with an out modifier is an output parameter. 参照パラメーターと同様に、出力パラメーターは新しいストレージの場所を作成しません。Similar to a reference parameter, an output parameter does not create a new storage location. 代わりに、出力パラメーターは、メソッド呼び出しで引数として指定された変数と同じ格納場所を表します。Instead, an output parameter represents the same storage location as the variable given as the argument in the method invocation.

仮パラメーターが出力パラメーターの場合、メソッド呼び出しの対応する引数は、キーワード out の後に、仮パラメーターと同じ型のvariable_reference (明確な代入を決定するための正確な規則) を指定する必要があります。When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable_reference (Precise rules for determining definite assignment) of the same type as the formal parameter. 変数は出力パラメーターとして渡す前に明示的に割り当てられている必要はありませんが、変数が出力パラメーターとして渡された場合の呼び出しに従うと、変数は確実に代入されたと見なされます。A variable need not be definitely assigned before it can be passed as an output parameter, but following an invocation where a variable was passed as an output parameter, the variable is considered definitely assigned.

ローカル変数と同じように、メソッド内では、出力パラメーターはまず未割り当てと見なされ、その値を使用する前に確実に代入する必要があります。Within a method, just like a local variable, an output parameter is initially considered unassigned and must be definitely assigned before its value is used.

メソッドが返される前に、メソッドのすべての出力パラメーターを確実に代入する必要があります。Every output parameter of a method must be definitely assigned before the method returns.

部分メソッド (部分メソッド) または反復子 (反復子) として宣言されたメソッドは、出力パラメーターを持つことができません。A method declared as a partial method (Partial methods) or an iterator (Iterators) cannot have output parameters.

出力パラメーターは、通常、複数の戻り値を生成するメソッドで使用されます。Output parameters are typically used in methods that produce multiple return values. 例 :For example:

using System;

class Test
{
    static void SplitPath(string path, out string dir, out string name) {
        int i = path.Length;
        while (i > 0) {
            char ch = path[i - 1];
            if (ch == '\\' || ch == '/' || ch == ':') break;
            i--;
        }
        dir = path.Substring(0, i);
        name = path.Substring(i);
    }

    static void Main() {
        string dir, name;
        SplitPath("c:\\Windows\\System\\hello.txt", out dir, out name);
        Console.WriteLine(dir);
        Console.WriteLine(name);
    }
}

この例では、次の出力が生成されます。The example produces the output:

c:\Windows\System\
hello.txt

dir 変数と name 変数は、SplitPathに渡す前に割り当てを解除することができ、呼び出し後に確実に割り当てられることに注意してください。Note that the dir and name variables can be unassigned before they are passed to SplitPath, and that they are considered definitely assigned following the call.

パラメーター配列Parameter arrays

params 修飾子で宣言されたパラメーターはパラメーター配列です。A parameter declared with a params modifier is a parameter array. 仮パラメーターリストにパラメーター配列が含まれている場合は、リストの最後のパラメーターである必要があり、それは1次元配列型である必要があります。If a formal parameter list includes a parameter array, it must be the last parameter in the list and it must be of a single-dimensional array type. たとえば、型 string[]string[][] はパラメーター配列の型として使用できますが、string[,] 型は使用できません。For example, the types string[] and string[][] can be used as the type of a parameter array, but the type string[,] can not. params 修飾子と修飾子 ref および outを組み合わせることはできません。It is not possible to combine the params modifier with the modifiers ref and out.

パラメーター配列では、メソッド呼び出しの2つの方法のいずれかで引数を指定できます。A parameter array permits arguments to be specified in one of two ways in a method invocation:

  • パラメーター配列に指定する引数には、暗黙的に変換可能な (暗黙の変換) 1 つの式をパラメーター配列型に指定できます。The argument given for a parameter array can be a single expression that is implicitly convertible (Implicit conversions) to the parameter array type. この場合、パラメーター配列は、値パラメーターとまったく同様に動作します。In this case, the parameter array acts precisely like a value parameter.
  • また、呼び出しでは、パラメーター配列に0個以上の引数を指定できます。各引数は、暗黙的に変換可能な式 (暗黙的な変換) で、パラメーター配列の要素型になります。Alternatively, the invocation can specify zero or more arguments for the parameter array, where each argument is an expression that is implicitly convertible (Implicit conversions) to the element type of the parameter array. この場合、呼び出しは、引数の数に対応する長さを持つパラメーター配列型のインスタンスを作成し、指定された引数値を使用して配列インスタンスの要素を初期化し、新しく作成された配列インスタンスを実際のとして使用します。引数.In this case, the invocation creates an instance of the parameter array type with a length corresponding to the number of arguments, initializes the elements of the array instance with the given argument values, and uses the newly created array instance as the actual argument.

呼び出しで可変個の引数を許可する場合を除き、パラメーター配列は、同じ型の値パラメーター (パラメーター) と厳密に等価です。Except for allowing a variable number of arguments in an invocation, a parameter array is precisely equivalent to a value parameter (Value parameters) of the same type.

The example

using System;

class Test
{
    static void F(params int[] args) {
        Console.Write("Array contains {0} elements:", args.Length);
        foreach (int i in args) 
            Console.Write(" {0}", i);
        Console.WriteLine();
    }

    static void Main() {
        int[] arr = {1, 2, 3};
        F(arr);
        F(10, 20, 30, 40);
        F();
    }
}

この例では、次のように出力されます。produces the output

Array contains 3 elements: 1 2 3
Array contains 4 elements: 10 20 30 40
Array contains 0 elements:

F の最初の呼び出しでは、単に配列 a を値パラメーターとして渡します。The first invocation of F simply passes the array a as a value parameter. F の2回目の呼び出しでは、指定された要素の値を持つ4つの要素 int[] が自動的に作成され、その配列インスタンスが値パラメーターとして渡されます。The second invocation of F automatically creates a four-element int[] with the given element values and passes that array instance as a value parameter. 同様に、F の3回目の呼び出しでは、ゼロ要素 int[] を作成し、そのインスタンスを値パラメーターとして渡します。Likewise, the third invocation of F creates a zero-element int[] and passes that instance as a value parameter. 2番目と3番目の呼び出しは、書き込みとまったく同じです。The second and third invocations are precisely equivalent to writing:

F(new int[] {10, 20, 30, 40});
F(new int[] {});

オーバーロードの解決を実行する場合、パラメーター配列を持つメソッドは、通常の形式または拡張された形式 (適用可能な関数メンバー) のいずれかに適用できます。When performing overload resolution, a method with a parameter array may be applicable either in its normal form or in its expanded form (Applicable function member). メソッドの拡張形式は、メソッドの通常の形式が適用されない場合にのみ使用できます。また、展開されたフォームと同じシグネチャを持つ適用可能なメソッドが、同じ型で宣言されていない場合にのみ使用できます。The expanded form of a method is available only if the normal form of the method is not applicable and only if an applicable method with the same signature as the expanded form is not already declared in the same type.

The example

using System;

class Test
{
    static void F(params object[] a) {
        Console.WriteLine("F(object[])");
    }

    static void F() {
        Console.WriteLine("F()");
    }

    static void F(object a0, object a1) {
        Console.WriteLine("F(object,object)");
    }

    static void Main() {
        F();
        F(1);
        F(1, 2);
        F(1, 2, 3);
        F(1, 2, 3, 4);
    }
}

この例では、次のように出力されます。produces the output

F();
F(object[]);
F(object,object);
F(object[]);
F(object[]);

この例では、パラメーター配列を使用するメソッドの拡張された2つの形式は、通常のメソッドとしてクラスに既に含まれています。In the example, two of the possible expanded forms of the method with a parameter array are already included in the class as regular methods. これらの拡張されたフォームは、オーバーロードの解決を実行するときには考慮されません。そのため、最初と3番目のメソッドの呼び出しでは、通常のメソッドを選択します。These expanded forms are therefore not considered when performing overload resolution, and the first and third method invocations thus select the regular methods. クラスがパラメーター配列を使用してメソッドを宣言する場合、一部の拡張されたフォームも通常のメソッドとして含めることは珍しくありません。When a class declares a method with a parameter array, it is not uncommon to also include some of the expanded forms as regular methods. これにより、パラメーター配列を持つメソッドの拡張された形式が呼び出されたときに発生する配列インスタンスの割り当てを回避できます。By doing so it is possible to avoid the allocation of an array instance that occurs when an expanded form of a method with a parameter array is invoked.

パラメーター配列の型が object[]場合、通常の形式のメソッドと1つの object パラメーターの使用可能な形式との間であいまいさが発生する可能性があります。When the type of a parameter array is object[], a potential ambiguity arises between the normal form of the method and the expended form for a single object parameter. あいまいさの理由は、object[] 自体が型 objectに暗黙的に変換できることです。The reason for the ambiguity is that an object[] is itself implicitly convertible to type object. ただし、あいまいさは、必要に応じてキャストを挿入することによって解決できるため、問題ありません。The ambiguity presents no problem, however, since it can be resolved by inserting a cast if needed.

The example

using System;

class Test
{
    static void F(params object[] args) {
        foreach (object o in args) {
            Console.Write(o.GetType().FullName);
            Console.Write(" ");
        }
        Console.WriteLine();
    }

    static void Main() {
        object[] a = {1, "Hello", 123.456};
        object o = a;
        F(a);
        F((object)a);
        F(o);
        F((object[])o);
    }
}

この例では、次のように出力されます。produces the output

System.Int32 System.String System.Double
System.Object[]
System.Object[]
System.Int32 System.String System.Double

Fの最初の呼び出しと最後の呼び出しでは、引数の型からパラメーターの型への暗黙的な変換が存在するため (両方とも object[]型)、F の通常の形式が適用されます。In the first and last invocations of F, the normal form of F is applicable because an implicit conversion exists from the argument type to the parameter type (both are of type object[]). したがって、オーバーロードの解決では、通常の形式の Fが選択され、引数は通常の値パラメーターとして渡されます。Thus, overload resolution selects the normal form of F, and the argument is passed as a regular value parameter. 2番目と3番目の呼び出しでは、引数の型からパラメーターの型への暗黙的な変換が存在しないため、通常の形式の F は適用できません (型 object を型 object[]に暗黙的に変換することはできません)。In the second and third invocations, the normal form of F is not applicable because no implicit conversion exists from the argument type to the parameter type (type object cannot be implicitly converted to type object[]). ただし、拡張された形式の F は適用可能なので、オーバーロードの解決によって選択されます。However, the expanded form of F is applicable, so it is selected by overload resolution. その結果、1要素の object[] が呼び出しによって作成され、配列の1つの要素が、指定された引数の値 (それ自体が object[]への参照) で初期化されます。As a result, a one-element object[] is created by the invocation, and the single element of the array is initialized with the given argument value (which itself is a reference to an object[]).

静的メソッドとインスタンス メソッドStatic and instance methods

メソッドの宣言に static 修飾子が含まれている場合、そのメソッドは静的メソッドと呼ばれます。When a method declaration includes a static modifier, that method is said to be a static method. static 修飾子が存在しない場合、メソッドはインスタンスメソッドと呼ばれます。When no static modifier is present, the method is said to be an instance method.

静的メソッドは、特定のインスタンスでは動作せず、静的メソッドで this を参照するコンパイル時エラーです。A static method does not operate on a specific instance, and it is a compile-time error to refer to this in a static method.

インスタンスメソッドは、クラスの特定のインスタンスに対して動作し、そのインスタンスには this (このアクセス) としてアクセスできます。An instance method operates on a given instance of a class, and that instance can be accessed as this (This access).

メソッドが E.Mフォームのmember_access (メンバーアクセス) で参照されている場合、M が静的メソッドである場合、EMを含む型を表している必要があり、M がインスタンスメソッドである場合、EMを含む型のインスタンスを示す必要があります。When a method is referenced in a member_access (Member access) of the form E.M, if M is a static method, E must denote a type containing M, and if M is an instance method, E must denote an instance of a type containing M.

静的メンバーとインスタンスメンバーの違いについては、「静的メンバーとインスタンスメンバー」で詳しく説明します。The differences between static and instance members are discussed further in Static and instance members.

仮想メソッドVirtual methods

インスタンスメソッドの宣言に virtual 修飾子が含まれている場合、そのメソッドは仮想メソッドと呼ばれます。When an instance method declaration includes a virtual modifier, that method is said to be a virtual method. virtual 修飾子が存在しない場合、メソッドは非仮想メソッドと呼ばれます。When no virtual modifier is present, the method is said to be a non-virtual method.

非仮想メソッドの実装は不変です。実装は、メソッドが宣言されているクラスのインスタンスまたは派生クラスのインスタンスで呼び出されているかどうかによって異なります。The implementation of a non-virtual method is invariant: The implementation is the same whether the method is invoked on an instance of the class in which it is declared or an instance of a derived class. これに対し、仮想メソッドの実装は、派生クラスによって置き換えることができます。In contrast, the implementation of a virtual method can be superseded by derived classes. 継承された仮想メソッドの実装を置き換えるプロセスは、そのメソッドのオーバーライド(メソッドのオーバーライド) と呼ばれます。The process of superseding the implementation of an inherited virtual method is known as overriding that method (Override methods).

仮想メソッドの呼び出しでは、呼び出し元のインスタンスの実行時の型によって、呼び出す実際のメソッドの実装が決まります。In a virtual method invocation, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke. 非仮想メソッドの呼び出しでは、インスタンスのコンパイル時の型が決定要因になります。In a non-virtual method invocation, the compile-time type of the instance is the determining factor. 正確に言えば、N という名前のメソッドが、コンパイル時の型 C で、実行時の型 R (RC または Cから派生したクラス) であるインスタンスに対して A 引数リストを使用して呼び出されると、呼び出しは次のように処理されます。In precise terms, when a method named N is invoked with an argument list A on an instance with a compile-time type C and a run-time type R (where R is either C or a class derived from C), the invocation is processed as follows:

  • 1つ目は、オーバーロードの解決を CN、および Aに適用して、で宣言され、Cによって継承されるメソッドのセットから特定のメソッド M を選択することです。First, overload resolution is applied to C, N, and A, to select a specific method M from the set of methods declared in and inherited by C. これについては、「メソッドの呼び出し」を参照してください。This is described in Method invocations.
  • 次に、M が非仮想メソッドの場合、M が呼び出されます。Then, if M is a non-virtual method, M is invoked.
  • それ以外の場合、M は仮想メソッドであり、R に関して最も派生する M の実装が呼び出されます。Otherwise, M is a virtual method, and the most derived implementation of M with respect to R is invoked.

クラスによって宣言または継承されているすべての仮想メソッドについて、そのクラスに対してメソッドの最も派生した実装が存在します。For every virtual method declared in or inherited by a class, there exists a most derived implementation of the method with respect to that class. クラス R に対して M 仮想メソッドの最も派生する実装は、次のように決定されます。The most derived implementation of a virtual method M with respect to a class R is determined as follows:

  • RMの導入 virtual 宣言が含まれている場合、これは Mの最も派生された実装です。If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
  • それ以外の場合、RMoverride が含まれている場合、これは Mの最も派生された実装です。Otherwise, if R contains an override of M, then this is the most derived implementation of M.
  • それ以外の場合、R に関して最も派生した M の実装は、Rの直接基底クラスに対する M の最も派生した実装と同じです。Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.

次の例では、仮想メソッドと非仮想メソッドの違いについて説明します。The following example illustrates the differences between virtual and non-virtual methods:

using System;

class A
{
    public void F() { Console.WriteLine("A.F"); }

    public virtual void G() { Console.WriteLine("A.G"); }
}

class B: A
{
    new public void F() { Console.WriteLine("B.F"); }

    public override void G() { Console.WriteLine("B.G"); }
}

class Test
{
    static void Main() {
        B b = new B();
        A a = b;
        a.F();
        b.F();
        a.G();
        b.G();
    }
}

この例では、A に、仮想メソッド以外の F と仮想メソッド Gが導入されています。In the example, A introduces a non-virtual method F and a virtual method G. クラス B は、新しい非仮想メソッド Fを導入し、継承された Fを非表示にします。また、継承されたメソッド Gもオーバーライドします。The class B introduces a new non-virtual method F, thus hiding the inherited F, and also overrides the inherited method G. この例では、次の出力が生成されます。The example produces the output:

A.F
B.F
B.G
B.G

ステートメント a.G()A.Gではなく B.Gを呼び出すことに注意してください。Notice that the statement a.G() invokes B.G, not A.G. これは、インスタンス (A) のコンパイル時の型ではなく、インスタンスの実行時の型 (B) が、呼び出す実際のメソッドの実装を決定するためです。This is because the run-time type of the instance (which is B), not the compile-time type of the instance (which is A), determines the actual method implementation to invoke.

メソッドは継承されたメソッドを隠すことができるため、クラスに同じシグネチャを持つ複数の仮想メソッドを含めることができます。Because methods are allowed to hide inherited methods, it is possible for a class to contain several virtual methods with the same signature. これにより、すべての派生メソッドが非表示になるため、あいまいさの問題はありません。This does not present an ambiguity problem, since all but the most derived method are hidden. この例では、In the example

using System;

class A
{
    public virtual void F() { Console.WriteLine("A.F"); }
}

class B: A
{
    public override void F() { Console.WriteLine("B.F"); }
}

class C: B
{
    new public virtual void F() { Console.WriteLine("C.F"); }
}

class D: C
{
    public override void F() { Console.WriteLine("D.F"); }
}

class Test
{
    static void Main() {
        D d = new D();
        A a = d;
        B b = d;
        C c = d;
        a.F();
        b.F();
        c.F();
        d.F();
    }
}

C クラスと D クラスには、A によって導入されたものと Cによって導入されたものの2つの仮想メソッドが含まれています。the C and D classes contain two virtual methods with the same signature: The one introduced by A and the one introduced by C. C によって導入されたメソッドは、Aから継承されたメソッドを非表示にします。The method introduced by C hides the method inherited from A. したがって、D のオーバーライド宣言は、Cによって導入されたメソッドよりも優先されるため、Aによって導入されたメソッドを D でオーバーライドすることはできません。Thus, the override declaration in D overrides the method introduced by C, and it is not possible for D to override the method introduced by A. この例では、次の出力が生成されます。The example produces the output:

B.F
B.F
D.F
D.F

メソッドが非表示にならない派生型を使用して D のインスタンスにアクセスすることによって、非表示の仮想メソッドを呼び出すことができることに注意してください。Note that it is possible to invoke the hidden virtual method by accessing an instance of D through a less derived type in which the method is not hidden.

オーバーライドメソッドOverride methods

インスタンスメソッドの宣言に override 修飾子が含まれている場合、メソッドはオーバーライドメソッドと呼ばれます。When an instance method declaration includes an override modifier, the method is said to be an override method. オーバーライドメソッドは、同じシグネチャを持つ継承された仮想メソッドをオーバーライドします。An override method overrides an inherited virtual method with the same signature. 仮想メソッドの宣言には新しいメソッドが導入されていますが、オーバーライド メソッドの宣言では、そのメソッドの新しい実装を提供することで既存の継承された仮想メソッドを特殊化します。Whereas a virtual method declaration introduces a new method, an override method declaration specializes an existing inherited virtual method by providing a new implementation of that method.

override 宣言によってオーバーライドされるメソッドは、オーバーライドされた基本メソッドと呼ばれます。The method overridden by an override declaration is known as the overridden base method. オーバーライドメソッド M クラス Cで宣言されている場合、オーバーライドされた基本メソッドは、1つ以上の基底クラス型の C``C を検査することによって決定されます。これは、指定された基底クラス型で、型引数の代入後に M と同じシグネチャを持つアクセス可能なメソッドが少なくとも1つ存在しますFor an override method M declared in a class C, the overridden base method is determined by examining each base class type of C, starting with the direct base class type of C and continuing with each successive direct base class type, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments. オーバーライドされた基本メソッドを検索するために、メソッドは、publicされている場合はアクセス可能と見なされます (protectedされている場合は、protected internalされていない場合、Cと同じプログラム内で internal および宣言されている場合)。For the purposes of locating the overridden base method, a method is considered accessible if it is public, if it is protected, if it is protected internal, or if it is internal and declared in the same program as C.

次のすべてがオーバーライド宣言に当てはまる場合を除き、コンパイル時エラーが発生します。A compile-time error occurs unless all of the following are true for an override declaration:

  • オーバーライドされた基本メソッドは、前述のように配置できます。An overridden base method can be located as described above.
  • このようなオーバーライドされた基本メソッドが1つだけあります。There is exactly one such overridden base method. この制限は、基底クラスの型が構築された型である場合にのみ有効です。型引数を代入すると、2つのメソッドのシグネチャが同じになります。This restriction has effect only if the base class type is a constructed type where the substitution of type arguments makes the signature of two methods the same.
  • オーバーライドされた基本メソッドは、virtual、abstract、または override メソッドです。The overridden base method is a virtual, abstract, or override method. 言い換えると、オーバーライドされた基本メソッドを静的または非仮想にすることはできません。In other words, the overridden base method cannot be static or non-virtual.
  • オーバーライドされた基本メソッドは、シールメソッドではありません。The overridden base method is not a sealed method.
  • オーバーライドメソッドとオーバーライドされた基本メソッドの戻り値の型は同じです。The override method and the overridden base method have the same return type.
  • オーバーライド宣言とオーバーライドされた基本メソッドに、同じアクセシビリティが宣言されています。The override declaration and the overridden base method have the same declared accessibility. つまり、オーバーライド宣言では、仮想メソッドのアクセシビリティを変更することはできません。In other words, an override declaration cannot change the accessibility of the virtual method. ただし、オーバーライドされた基本メソッドが内部で保護されていて、オーバーライドメソッドを含むアセンブリとは別のアセンブリで宣言されている場合は、オーバーライドメソッドで宣言されたアクセシビリティを保護する必要があります。However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override method then the override method's declared accessibility must be protected.
  • オーバーライド宣言で、型パラメーターの制約句が指定されていません。The override declaration does not specify type-parameter-constraints-clauses. 代わりに、制約はオーバーライドされた基本メソッドから継承されます。Instead the constraints are inherited from the overridden base method. オーバーライドされたメソッドの型パラメーターである制約は、継承された制約の型引数によって置き換えられる可能性があることに注意してください。Note that constraints that are type parameters in the overridden method may be replaced by type arguments in the inherited constraint. これは、値型やシール型など、明示的に指定された場合には無効な制約につながる可能性があります。This can lead to constraints that are not legal when explicitly specified, such as value types or sealed types.

次の例は、ジェネリッククラスでのオーバーライド規則のしくみを示しています。The following example demonstrates how the overriding rules work for generic classes:

abstract class C<T>
{
    public virtual T F() {...}
    public virtual C<T> G() {...}
    public virtual void H(C<T> x) {...}
}

class D: C<string>
{
    public override string F() {...}            // Ok
    public override C<string> G() {...}         // Ok
    public override void H(C<T> x) {...}        // Error, should be C<string>
}

class E<T,U>: C<U>
{
    public override U F() {...}                 // Ok
    public override C<U> G() {...}              // Ok
    public override void H(C<T> x) {...}        // Error, should be C<U>
}

オーバーライド宣言は、 base_access (ベースアクセス) を使用して、オーバーライドされた基本メソッドにアクセスできます。An override declaration can access the overridden base method using a base_access (Base access). この例では、In the example

class A
{
    int x;

    public virtual void PrintFields() {
        Console.WriteLine("x = {0}", x);
    }
}

class B: A
{
    int y;

    public override void PrintFields() {
        base.PrintFields();
        Console.WriteLine("y = {0}", y);
    }
}

B での base.PrintFields() の呼び出しでは、Aで宣言された PrintFields メソッドが呼び出されます。the base.PrintFields() invocation in B invokes the PrintFields method declared in A. Base_accessは、仮想呼び出し機構を無効にし、単に基本メソッドを非仮想メソッドとして扱います。A base_access disables the virtual invocation mechanism and simply treats the base method as a non-virtual method. B の呼び出しが ((A)this).PrintFields()書き込まれている場合、Aが仮想であり、PrintFields の実行時の型が ((A)this) であるため、Bで宣言されたメソッドではなく Bで宣言されている PrintFields メソッドを再帰的に呼び出します。Had the invocation in B been written ((A)this).PrintFields(), it would recursively invoke the PrintFields method declared in B, not the one declared in A, since PrintFields is virtual and the run-time type of ((A)this) is B.

override 修飾子を含めることによってのみ、メソッドが別のメソッドをオーバーライドできます。Only by including an override modifier can a method override another method. それ以外の場合、継承されたメソッドと同じシグネチャを持つメソッドは、継承されたメソッドを非表示にします。In all other cases, a method with the same signature as an inherited method simply hides the inherited method. この例では、In the example

class A
{
    public virtual void F() {}
}

class B: A
{
    public virtual void F() {}        // Warning, hiding inherited F()
}

BF メソッドには、override 修飾子が含まれていないため、AF メソッドはオーバーライドされません。the F method in B does not include an override modifier and therefore does not override the F method in A. 代わりに、BF メソッドによって Aのメソッドが非表示になり、宣言に new 修飾子が含まれていないため、警告が報告されます。Rather, the F method in B hides the method in A, and a warning is reported because the declaration does not include a new modifier.

この例では、In the example

class A
{
    public virtual void F() {}
}

class B: A
{
    new private void F() {}        // Hides A.F within body of B
}

class C: B
{
    public override void F() {}    // Ok, overrides A.F
}

BF メソッドは、Aから継承された仮想 F メソッドを非表示にします。the F method in B hides the virtual F method inherited from A. B の新しい F にはプライベートアクセスがあるため、そのスコープには B のクラス本体のみが含まれ、Cには拡張されません。Since the new F in B has private access, its scope only includes the class body of B and does not extend to C. したがって、C 内の F の宣言は、Aから継承された F をオーバーライドできます。Therefore, the declaration of F in C is permitted to override the F inherited from A.

シールメソッドSealed methods

インスタンスメソッドの宣言に sealed 修飾子が含まれている場合、そのメソッドはsealed メソッドと呼ばれます。When an instance method declaration includes a sealed modifier, that method is said to be a sealed method. インスタンスメソッドの宣言に sealed 修飾子が含まれている場合は、override 修飾子も含める必要があります。If an instance method declaration includes the sealed modifier, it must also include the override modifier. sealed 修飾子を使用すると、派生クラスでメソッドをさらにオーバーライドできなくなります。Use of the sealed modifier prevents a derived class from further overriding the method.

この例では、In the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }

    public virtual void G() {
        Console.WriteLine("A.G");
    }
}

class B: A
{
    sealed override public void F() {
        Console.WriteLine("B.F");
    } 

    override public void G() {
        Console.WriteLine("B.G");
    } 
}

class C: B
{
    override public void G() {
        Console.WriteLine("C.G");
    } 
}

クラス B には、2つのオーバーライドメソッドが用意されています。 sealed 修飾子を持つ F メソッドと、それ以外の G メソッドです。the class B provides two override methods: an F method that has the sealed modifier and a G method that does not. シールされた modifier を使用 Bと、Fをさらにオーバーライドできなく C なります。B's use of the sealed modifier prevents C from further overriding F.

抽象メソッドAbstract methods

インスタンスメソッドの宣言に abstract 修飾子が含まれている場合、そのメソッドは抽象メソッドと呼ばれます。When an instance method declaration includes an abstract modifier, that method is said to be an abstract method. 抽象メソッドは暗黙的に仮想メソッドでもありますが、修飾子 virtualを持つことはできません。Although an abstract method is implicitly also a virtual method, it cannot have the modifier virtual.

抽象メソッドの宣言では、新しい仮想メソッドが導入されていますが、そのメソッドの実装は提供していません。An abstract method declaration introduces a new virtual method but does not provide an implementation of that method. 代わりに、抽象でない派生クラスは、そのメソッドをオーバーライドすることによって独自の実装を提供する必要があります。Instead, non-abstract derived classes are required to provide their own implementation by overriding that method. 抽象メソッドは実際の実装を提供しないため、抽象メソッドのmethod_bodyは単純にセミコロンで構成されます。Because an abstract method provides no actual implementation, the method_body of an abstract method simply consists of a semicolon.

抽象メソッドの宣言は、抽象クラス (抽象クラス) でのみ許可されます。Abstract method declarations are only permitted in abstract classes (Abstract classes).

この例では、In the example

public abstract class Shape
{
    public abstract void Paint(Graphics g, Rectangle r);
}

public class Ellipse: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawEllipse(r);
    }
}

public class Box: Shape
{
    public override void Paint(Graphics g, Rectangle r) {
        g.DrawRect(r);
    }
}

Shape クラスは、それ自体を描画できる幾何学図形オブジェクトの抽象概念を定義します。the Shape class defines the abstract notion of a geometrical shape object that can paint itself. Paint メソッドは abstract です。これは、意味のある既定の実装が存在しないためです。The Paint method is abstract because there is no meaningful default implementation. Ellipse クラスと Box クラスは、具体的な Shape 実装です。The Ellipse and Box classes are concrete Shape implementations. これらのクラスは非抽象であるため、Paint メソッドをオーバーライドし、実際の実装を提供する必要があります。Because these classes are non-abstract, they are required to override the Paint method and provide an actual implementation.

Base_access (ベースアクセス) が抽象メソッドを参照する場合、コンパイル時エラーになります。It is a compile-time error for a base_access (Base access) to reference an abstract method. この例では、In the example

abstract class A
{
    public abstract void F();
}

class B: A
{
    public override void F() {
        base.F();                        // Error, base.F is abstract
    }
}

base.F() の呼び出しでは、抽象メソッドを参照しているため、コンパイル時エラーが報告されます。a compile-time error is reported for the base.F() invocation because it references an abstract method.

抽象メソッドの宣言では、仮想メソッドをオーバーライドできます。An abstract method declaration is permitted to override a virtual method. これにより、抽象クラスは派生クラスのメソッドを強制的に再実装できるようになり、メソッドの元の実装を使用できなくなります。This allows an abstract class to force re-implementation of the method in derived classes, and makes the original implementation of the method unavailable. この例では、In the example

using System;

class A
{
    public virtual void F() {
        Console.WriteLine("A.F");
    }
}

abstract class B: A
{
    public abstract override void F();
}

class C: B
{
    public override void F() {
        Console.WriteLine("C.F");
    }
}

クラス A は仮想メソッドを宣言し、クラス B は抽象メソッドを使用してこのメソッドをオーバーライドし、クラス C は抽象メソッドをオーバーライドして独自の実装を提供します。class A declares a virtual method, class B overrides this method with an abstract method, and class C overrides the abstract method to provide its own implementation.

外部メソッドExternal methods

メソッドの宣言に extern 修飾子が含まれている場合、そのメソッドは外部メソッドと呼ばれます。When a method declaration includes an extern modifier, that method is said to be an external method. 外部メソッドは、通常以外C#の言語を使用して、外部で実装されます。External methods are implemented externally, typically using a language other than C#. 外部メソッドの宣言は実際の実装を提供しないため、外部メソッドのmethod_bodyは単純にセミコロンで構成されます。Because an external method declaration provides no actual implementation, the method_body of an external method simply consists of a semicolon. 外部メソッドはジェネリックではない可能性があります。An external method may not be generic.

extern 修飾子は通常、DllImport 属性 (COM コンポーネントおよび Win32 コンポーネントとの相互運用) と共に使用され、外部メソッドを Dll (ダイナミックリンクライブラリ) によって実装できます。The extern modifier is typically used in conjunction with a DllImport attribute (Interoperation with COM and Win32 components), allowing external methods to be implemented by DLLs (Dynamic Link Libraries). 実行環境では、外部メソッドの実装を提供できる他のメカニズムがサポートされている場合があります。The execution environment may support other mechanisms whereby implementations of external methods can be provided.

外部メソッドに DllImport 属性が含まれている場合、メソッドの宣言にも static 修飾子を含める必要があります。When an external method includes a DllImport attribute, the method declaration must also include a static modifier. この例では、extern 修飾子と DllImport 属性の使用方法を示します。This example demonstrates the use of the extern modifier and the DllImport attribute:

using System.Text;
using System.Security.Permissions;
using System.Runtime.InteropServices;

class Path
{
    [DllImport("kernel32", SetLastError=true)]
    static extern bool CreateDirectory(string name, SecurityAttribute sa);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool RemoveDirectory(string name);

    [DllImport("kernel32", SetLastError=true)]
    static extern int GetCurrentDirectory(int bufSize, StringBuilder buf);

    [DllImport("kernel32", SetLastError=true)]
    static extern bool SetCurrentDirectory(string name);
}

部分メソッド (要約)Partial methods (recap)

メソッドの宣言に partial 修飾子が含まれている場合、そのメソッドは部分メソッドと呼ばれます。When a method declaration includes a partial modifier, that method is said to be a partial method. 部分メソッドは、部分型 (部分型) のメンバーとしてのみ宣言でき、いくつかの制限が適用されます。Partial methods can only be declared as members of partial types (Partial types), and are subject to a number of restrictions. 部分メソッドの詳細については、部分メソッドを参照してください。Partial methods are further described in Partial methods.

拡張メソッドExtension methods

メソッドの最初のパラメーターに this 修飾子が含まれている場合、そのメソッドは拡張メソッドと呼ばれます。When the first parameter of a method includes the this modifier, that method is said to be an extension method. 拡張メソッドは、非ジェネリックで入れ子にされていない静的クラスでのみ宣言できます。Extension methods can only be declared in non-generic, non-nested static classes. 拡張メソッドの最初のパラメーターには、this以外の修飾子を指定できません。また、パラメーターの型をポインター型にすることはできません。The first parameter of an extension method can have no modifiers other than this, and the parameter type cannot be a pointer type.

2つの拡張メソッドを宣言する静的クラスの例を次に示します。The following is an example of a static class that declares two extension methods:

public static class Extensions
{
    public static int ToInt32(this string s) {
        return Int32.Parse(s);
    }

    public static T[] Slice<T>(this T[] source, int index, int count) {
        if (index < 0 || count < 0 || source.Length - index < count)
            throw new ArgumentException();
        T[] result = new T[count];
        Array.Copy(source, index, result, 0, count);
        return result;
    }
}

拡張メソッドは、通常の静的メソッドです。An extension method is a regular static method. また、外側の静的クラスがスコープ内にある場合、最初の引数としてレシーバー式を使用して、インスタンスメソッドの呼び出し構文 (拡張メソッドの呼び出し) を使用して拡張メソッドを呼び出すことができます。In addition, where its enclosing static class is in scope, an extension method can be invoked using instance method invocation syntax (Extension method invocations), using the receiver expression as the first argument.

次のプログラムでは、上記で宣言した拡張メソッドを使用します。The following program uses the extension methods declared above:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in strings.Slice(1, 2)) {
            Console.WriteLine(s.ToInt32());
        }
    }
}

Slice メソッドは string[]で使用でき、ToInt32 メソッドは、拡張メソッドとして宣言されているため、stringで使用できます。The Slice method is available on the string[], and the ToInt32 method is available on string, because they have been declared as extension methods. プログラムの意味は、通常の静的メソッド呼び出しを使用した次のようになります。The meaning of the program is the same as the following, using ordinary static method calls:

static class Program
{
    static void Main() {
        string[] strings = { "1", "22", "333", "4444" };
        foreach (string s in Extensions.Slice(strings, 1, 2)) {
            Console.WriteLine(Extensions.ToInt32(s));
        }
    }
}

メソッド本体Method body

メソッド宣言のmethod_bodyは、ブロック本体、式本体、またはセミコロンで構成されます。The method_body of a method declaration consists of either a block body, an expression body or a semicolon.

戻り値の型が voidの場合、またはメソッドが非同期で戻り値の型が System.Threading.Tasks.Task場合は、メソッドの結果型void ます。The result type of a method is void if the return type is void, or if the method is async and the return type is System.Threading.Tasks.Task. それ以外の場合、非同期メソッド以外のメソッドの結果型は戻り値の型になり、戻り値の型が System.Threading.Tasks.Task<T> の非同期メソッドの結果の型は Tになります。Otherwise, the result type of a non-async method is its return type, and the result type of an async method with return type System.Threading.Tasks.Task<T> is T.

メソッドに void の結果型とブロック本体がある場合、ブロック内の return ステートメント (return ステートメント) で式を指定することはできません。When a method has a void result type and a block body, return statements (The return statement) in the block are not permitted to specify an expression. Void メソッドのブロックの実行が正常に完了した場合 (つまり、制御フローがメソッド本体の末尾から離れた場合)、そのメソッドは単に現在の呼び出し元に戻ります。If execution of the block of a void method completes normally (that is, control flows off the end of the method body), that method simply returns to its current caller.

メソッドに void の結果と式の本体が含まれている場合、E 式はstatement_expressionである必要があり、本文は { E; }フォームのブロック本体とまったく同じになります。When a method has a void result and an expression body, the expression E must be a statement_expression, and the body is exactly equivalent to a block body of the form { E; }.

メソッドに void 以外の結果型とブロック本体がある場合、ブロック内の各 return ステートメントで、結果型に暗黙的に変換できる式を指定する必要があります。When a method has a non-void result type and a block body, each return statement in the block must specify an expression that is implicitly convertible to the result type. 値を返すメソッドのブロック本体のエンドポイントに到達できません。The endpoint of a block body of a value-returning method must not be reachable. つまり、ブロック本体を持つ値を返すメソッドでは、コントロールはメソッド本体の末尾から制御できません。In other words, in a value-returning method with a block body, control is not permitted to flow off the end of the method body.

メソッドが void 以外の結果型と式本体を持つ場合、式は結果型に暗黙的に変換できる必要があり、本文は { return E; }フォームのブロック本体とまったく同じになります。When a method has a non-void result type and an expression body, the expression must be implicitly convertible to the result type, and the body is exactly equivalent to a block body of the form { return E; }.

この例では、In the example

class A
{
    public int F() {}            // Error, return value required

    public int G() {
        return 1;
    }

    public int H(bool b) {
        if (b) {
            return 1;
        }
        else {
            return 0;
        }
    }

    public int I(bool b) => b ? 1 : 0;
}

コントロールはメソッド本体の末尾から制御できるため、値を返す F メソッドはコンパイル時エラーになります。the value-returning F method results in a compile-time error because control can flow off the end of the method body. 使用可能なすべての実行パスが戻り値を指定する return ステートメントで終了するため、G および H メソッドは正しいです。The G and H methods are correct because all possible execution paths end in a return statement that specifies a return value. I メソッドが正しいのは、その本体が1つの return ステートメントだけを含むステートメントブロックと同じであるためです。The I method is correct, because its body is equivalent to a statement block with just a single return statement in it.

メソッドのオーバーロードMethod overloading

メソッドのオーバーロードの解決規則については、 「型の推定」を参照してください。The method overload resolution rules are described in Type inference.

プロパティProperties

プロパティは、オブジェクトまたはクラスの特性へのアクセスを提供するメンバーです。A property is a member that provides access to a characteristic of an object or a class. プロパティの例としては、文字列の長さ、フォントのサイズ、ウィンドウのキャプション、顧客名などがあります。Examples of properties include the length of a string, the size of a font, the caption of a window, the name of a customer, and so on. プロパティはフィールドの自然な拡張機能であり、どちらも、関連付けられた型を持つ名前付きのメンバーであり、フィールドとプロパティにアクセスするための構文は同じです。Properties are a natural extension of fields—both are named members with associated types, and the syntax for accessing fields and properties is the same. ただし、フィールドとは異なり、プロパティは格納場所を表しません。However, unlike fields, properties do not denote storage locations. その代わりに、プロパティには、値の読み取りまたは書き込みの際に実行されるステートメントを指定する "アクセサー" があります。Instead, properties have accessors that specify the statements to be executed when their values are read or written. そのため、プロパティは、アクションをオブジェクトの属性の読み取りと書き込みに関連付けるメカニズムを提供します。さらに、このような属性を計算することもできます。Properties thus provide a mechanism for associating actions with the reading and writing of an object's attributes; furthermore, they permit such attributes to be computed.

プロパティはproperty_declarations を使用して宣言されます。Properties are declared using property_declarations:

property_declaration
    : attributes? property_modifier* type member_name property_body
    ;

property_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | property_modifier_unsafe
    ;

property_body
    : '{' accessor_declarations '}' property_initializer?
    | '=>' expression ';'
    ;

property_initializer
    : '=' variable_initializer ';'
    ;

Property_declarationには、属性(属性) のセットと、4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせ、new (新しい修飾子)、static (静的メソッドとインスタンスメソッド)、virtual (仮想メソッド)、override (オーバーライドメソッド)、(シールメソッド)、sealed (抽象メソッド)、および abstract (外部メソッド) 修飾子を含めることができます。externA property_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

プロパティ宣言は、修飾子の有効な組み合わせに関して、メソッド宣言 (メソッド) と同じ規則に従います。Property declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

プロパティ宣言のは、宣言によって導入されるプロパティの型を指定し、 member_nameはプロパティの名前を指定します。The type of a property declaration specifies the type of the property introduced by the declaration, and the member_name specifies the name of the property. プロパティが明示的なインターフェイスメンバーの実装でない限り、 member_nameは単なる識別子です。Unless the property is an explicit interface member implementation, the member_name is simply an identifier. 明示的なインターフェイスメンバーの実装 (明示的なインターフェイスメンバーの実装) の場合、 member_nameinterface_typeの後に "." と識別子が続く形式で構成されます。For an explicit interface member implementation (Explicit interface member implementations), the member_name consists of an interface_type followed by a "." and an identifier.

プロパティのは、少なくともプロパティ自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The type of a property must be at least as accessible as the property itself (Accessibility constraints).

Property_bodyは、アクセサー本体または式の本体で構成されている場合があります。A property_body may either consist of an accessor body or an expression body. アクセサー本体で、 accessor_declarationsを "{" および "}" トークンで囲む必要がある場合は、プロパティのアクセサー (アクセサー) を宣言します。In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. アクセサーは、プロパティの読み取りと書き込みに関連付けられた実行可能なステートメントを指定します。The accessors specify the executable statements associated with reading and writing the property.

=> で構成され、その後にE が続く式本体と、セミコロンはステートメント本体 { get { return E; } }と完全に等価であり、そのため、getter の結果が1つの式によって指定される getter のみのプロパティを指定する場合にのみ使用できます。An expression body consisting of => followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only properties where the result of the getter is given by a single expression.

Property_initializerは、自動的に実装されるプロパティ (自動的に実装されるプロパティ) に対してのみ指定でき、そのようなプロパティの基になるフィールドは、によって指定された値で初期化されます。A property_initializer may only be given for an automatically implemented property (Automatically implemented properties), and causes the initialization of the underlying field of such properties with the value given by the expression.

プロパティにアクセスするための構文は、フィールドの場合と同じですが、プロパティは変数として分類されません。Even though the syntax for accessing a property is the same as that for a field, a property is not classified as a variable. したがって、プロパティを ref または out 引数として渡すことはできません。Thus, it is not possible to pass a property as a ref or out argument.

プロパティの宣言に extern 修飾子が含まれている場合、プロパティは外部プロパティと呼ばれます。When a property declaration includes an extern modifier, the property is said to be an external property. 外部プロパティの宣言は実際の実装を提供しないため、各accessor_declarationsはセミコロンで構成されます。Because an external property declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

静的プロパティとインスタンスプロパティStatic and instance properties

プロパティの宣言に static 修飾子が含まれている場合、プロパティは静的プロパティと呼ばれます。When a property declaration includes a static modifier, the property is said to be a static property. static 修飾子が存在しない場合、プロパティはインスタンスプロパティと呼ばれます。When no static modifier is present, the property is said to be an instance property.

静的プロパティは特定のインスタンスに関連付けられていません。静的なプロパティのアクセサーで this を参照するには、コンパイル時エラーになります。A static property is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static property.

インスタンスプロパティは、クラスの特定のインスタンスに関連付けられます。このインスタンスには、そのプロパティのアクセサーで this (このアクセス) としてアクセスできます。An instance property is associated with a given instance of a class, and that instance can be accessed as this (This access) in the accessors of that property.

プロパティが E.Mフォームのmember_access (メンバーアクセス) で参照されている場合、M が静的プロパティである場合、EMを含む型を示す必要があります。また、M がインスタンスプロパティの場合、E は Mを含む型のインスタンスを示す必要があります。When a property is referenced in a member_access (Member access) of the form E.M, if M is a static property, E must denote a type containing M, and if M is an instance property, E must denote an instance of a type containing M.

静的メンバーとインスタンスメンバーの違いについては、「静的メンバーとインスタンスメンバー」で詳しく説明します。The differences between static and instance members are discussed further in Static and instance members.

アクセスAccessors

プロパティのaccessor_declarationsは、そのプロパティの読み取りと書き込みに関連付けられた実行可能なステートメントを指定します。The accessor_declarations of a property specify the executable statements associated with reading and writing that property.

accessor_declarations
    : get_accessor_declaration set_accessor_declaration?
    | set_accessor_declaration get_accessor_declaration?
    ;

get_accessor_declaration
    : attributes? accessor_modifier? 'get' accessor_body
    ;

set_accessor_declaration
    : attributes? accessor_modifier? 'set' accessor_body
    ;

accessor_modifier
    : 'protected'
    | 'internal'
    | 'private'
    | 'protected' 'internal'
    | 'internal' 'protected'
    ;

accessor_body
    : block
    | ';'
    ;

アクセサー宣言は、 get_accessor_declarationset_accessor_declaration、またはその両方で構成されます。The accessor declarations consist of a get_accessor_declaration, a set_accessor_declaration, or both. 各アクセサー宣言は、トークン get または set の後に省略可能なaccessor_modifieraccessor_bodyで構成されます。Each accessor declaration consists of the token get or set followed by an optional accessor_modifier and an accessor_body.

Accessor_modifiers の使用には、次の制限が適用されます。The use of accessor_modifiers is governed by the following restrictions:

  • Accessor_modifierは、インターフェイスまたは明示的なインターフェイスメンバーの実装では使用できません。An accessor_modifier may not be used in an interface or in an explicit interface member implementation.
  • override 修飾子を持たないプロパティまたはインデクサーの場合、 accessor_modifierは、プロパティまたはインデクサーに getset の両方のアクセサーが含まれている場合にのみ許可されます。その後、これらのアクセサーのいずれかでのみ許可されます。For a property or indexer that has no override modifier, an accessor_modifier is permitted only if the property or indexer has both a get and set accessor, and then is permitted only on one of those accessors.
  • override 修飾子を含むプロパティまたはインデクサーの場合、アクセサーはオーバーライドされるアクセサーのaccessor_modifierと一致する必要があります。For a property or indexer that includes an override modifier, an accessor must match the accessor_modifier, if any, of the accessor being overridden.
  • Accessor_modifierは、プロパティまたはインデクサー自体の宣言されたアクセシビリティより厳密に制限されたアクセシビリティを宣言する必要があります。The accessor_modifier must declare an accessibility that is strictly more restrictive than the declared accessibility of the property or indexer itself. 正確である必要があります。To be precise:
    • プロパティまたはインデクサーに publicのアクセシビリティが宣言されている場合、 accessor_modifierprotected internalinternalprotectedprivateのいずれかになります。If the property or indexer has a declared accessibility of public, the accessor_modifier may be either protected internal, internal, protected, or private.
    • プロパティまたはインデクサーに protected internalのアクセシビリティが宣言されている場合、 accessor_modifierinternalprotected、または privateのいずれかになります。If the property or indexer has a declared accessibility of protected internal, the accessor_modifier may be either internal, protected, or private.
    • プロパティまたはインデクサーに internal または protectedの宣言されたアクセシビリティがある場合、 accessor_modifierprivateする必要があります。If the property or indexer has a declared accessibility of internal or protected, the accessor_modifier must be private.
    • プロパティまたはインデクサーに privateのアクセシビリティが宣言されている場合、 accessor_modifierを使用することはできません。If the property or indexer has a declared accessibility of private, no accessor_modifier may be used.

abstract および extern プロパティの場合、指定された各アクセサーのaccessor_bodyは、単純にセミコロンになります。For abstract and extern properties, the accessor_body for each accessor specified is simply a semicolon. 非抽象型の非 extern プロパティは、各accessor_bodyをセミコロンにすることができます。この場合、自動的に実装されるプロパティ (自動的に実装されるプロパティ) です。A non-abstract, non-extern property may have each accessor_body be a semicolon, in which case it is an automatically implemented property (Automatically implemented properties). 自動的に実装されるプロパティには、少なくとも get アクセサーが必要です。An automatically implemented property must have at least a get accessor. 他の非抽象、非 extern プロパティのアクセサーの場合、 accessor_bodyは、対応するアクセサーが呼び出されたときに実行されるステートメントを指定するブロックです。For the accessors of any other non-abstract, non-extern property, the accessor_body is a block which specifies the statements to be executed when the corresponding accessor is invoked.

get アクセサーは、プロパティの型の戻り値を持つパラメーターなしのメソッドに対応します。A get accessor corresponds to a parameterless method with a return value of the property type. 代入の対象として、プロパティが式で参照されている場合は、プロパティの get アクセサーが呼び出され、プロパティ (式の値) の値が計算されます。Except as the target of an assignment, when a property is referenced in an expression, the get accessor of the property is invoked to compute the value of the property (Values of expressions). get アクセサーの本体は、「メソッド本体」で説明されている値を返すメソッドの規則に準拠している必要があります。The body of a get accessor must conform to the rules for value-returning methods described in Method body. 特に、get アクセサーの本体にあるすべての return ステートメントでは、プロパティの型に暗黙的に変換できる式を指定する必要があります。In particular, all return statements in the body of a get accessor must specify an expression that is implicitly convertible to the property type. さらに、get アクセサーのエンドポイントに到達できないようにする必要があります。Furthermore, the endpoint of a get accessor must not be reachable.

set アクセサーは、プロパティ型の単一の値パラメーターと void の戻り値の型を持つメソッドに対応します。A set accessor corresponds to a method with a single value parameter of the property type and a void return type. set アクセサーの暗黙的なパラメーターには、常に valueという名前が付けられます。The implicit parameter of a set accessor is always named value. プロパティが代入式のターゲットとして参照されている場合 (代入演算子)、または、++ または -- のオペランド (後置インクリメントおよびデクリメント演算子前置インクリメントおよびデクリメント演算子) として、set アクセサーは、新しい値 (単純な代入) を提供する引数 (代入の右辺の値または ++ または -- 演算子のオペランド) を使用して呼び出されます。When a property is referenced as the target of an assignment (Assignment operators), or as the operand of ++ or -- (Postfix increment and decrement operators, Prefix increment and decrement operators), the set accessor is invoked with an argument (whose value is that of the right-hand side of the assignment or the operand of the ++ or -- operator) that provides the new value (Simple assignment). set アクセサーの本体は、「メソッド本体」で説明されている void メソッドの規則に準拠している必要があります。The body of a set accessor must conform to the rules for void methods described in Method body. 特に、set アクセサー本体の return ステートメントでは、式を指定することはできません。In particular, return statements in the set accessor body are not permitted to specify an expression. set アクセサーには valueという名前のパラメーターが暗黙的に含まれているため、set アクセサー内のローカル変数または定数宣言でその名前が使用される場合、コンパイル時エラーになります。Since a set accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declaration in a set accessor to have that name.

getset のアクセサーの有無に基づいて、プロパティは次のように分類されます。Based on the presence or absence of the get and set accessors, a property is classified as follows:

  • get アクセサーと set アクセサーの両方を含むプロパティは、読み取り/書き込みプロパティと呼ばれます。A property that includes both a get accessor and a set accessor is said to be a read-write property.
  • get アクセサーだけを持つプロパティは、読み取り専用プロパティと呼ばれます。A property that has only a get accessor is said to be a read-only property. 読み取り専用プロパティが割り当てのターゲットである場合、コンパイル時エラーになります。It is a compile-time error for a read-only property to be the target of an assignment.
  • set のアクセサーだけを持つプロパティは、書き込み専用のプロパティと呼ばれます。A property that has only a set accessor is said to be a write-only property. 代入の対象となる場合を除き、式の書き込み専用プロパティを参照するコンパイル時エラーになります。Except as the target of an assignment, it is a compile-time error to reference a write-only property in an expression.

この例では、In the example

public class Button: Control
{
    private string caption;

    public string Caption {
        get {
            return caption;
        }
        set {
            if (caption != value) {
                caption = value;
                Repaint();
            }
        }
    }

    public override void Paint(Graphics g, Rectangle r) {
        // Painting code goes here
    }
}

Button コントロールは、パブリック Caption プロパティを宣言します。the Button control declares a public Caption property. Caption プロパティの get アクセサーは、private caption フィールドに格納されている文字列を返します。The get accessor of the Caption property returns the string stored in the private caption field. set アクセサーは、新しい値が現在の値と異なるかどうかを確認します。存在する場合は、新しい値を格納し、コントロールを再描画します。The set accessor checks if the new value is different from the current value, and if so, it stores the new value and repaints the control. プロパティは、多くの場合、上記のパターンに従います。 get アクセサーは、プライベートフィールドに格納されている値を返すだけで、set アクセサーはそのプライベートフィールドを変更し、オブジェクトの状態を完全に更新するために必要な追加のアクションを実行します。Properties often follow the pattern shown above: The get accessor simply returns a value stored in a private field, and the set accessor modifies that private field and then performs any additional actions required to fully update the state of the object.

上記の Button クラスを使用した場合、Caption プロパティの使用例を次に示します。Given the Button class above, the following is an example of use of the Caption property:

Button okButton = new Button();
okButton.Caption = "OK";            // Invokes set accessor
string s = okButton.Caption;        // Invokes get accessor

ここでは、プロパティに値を割り当てることによって set アクセサーが呼び出され、式のプロパティを参照することによって get アクセサーが呼び出されます。Here, the set accessor is invoked by assigning a value to the property, and the get accessor is invoked by referencing the property in an expression.

プロパティの get アクセサーと set アクセサーは、個別のメンバーではなく、プロパティのアクセサーを個別に宣言することはできません。The get and set accessors of a property are not distinct members, and it is not possible to declare the accessors of a property separately. そのため、読み取り/書き込みプロパティの2つのアクセサーが異なるアクセシビリティを持つことはできません。As such, it is not possible for the two accessors of a read-write property to have different accessibility. The example

class A
{
    private string name;

    public string Name {                // Error, duplicate member name
        get { return name; }
    }

    public string Name {                // Error, duplicate member name
        set { name = value; }
    }
}

は、1つの読み取り/書き込みプロパティを宣言しません。does not declare a single read-write property. 代わりに、同じ名前の2つのプロパティを宣言します。1つは読み取り専用で、もう1つは書き込み専用です。Rather, it declares two properties with the same name, one read-only and one write-only. 同じクラスで宣言された2つのメンバーは同じ名前を持つことができないため、この例ではコンパイル時エラーが発生します。Since two members declared in the same class cannot have the same name, the example causes a compile-time error to occur.

派生クラスで、継承されたプロパティと同じ名前のプロパティが宣言されている場合、派生プロパティは、読み取りと書き込みの両方に関して継承されたプロパティを非表示にします。When a derived class declares a property by the same name as an inherited property, the derived property hides the inherited property with respect to both reading and writing. この例では、In the example

class A
{
    public int P {
        set {...}
    }
}

class B: A
{
    new public int P {
        get {...}
    }
}

BP プロパティは、読み取りと書き込みの両方に対して AP プロパティを非表示にします。the P property in B hides the P property in A with respect to both reading and writing. そのため、ステートメントでは、Thus, in the statements

B b = new B();
b.P = 1;          // Error, B.P is read-only
((A)b).P = 1;     // Ok, reference to A.P

b.P への割り当てにより、コンパイル時エラーが報告されます。これは B の読み取り専用 P プロパティによって Aの書き込み専用 P プロパティが非表示になるためです。the assignment to b.P causes a compile-time error to be reported, since the read-only P property in B hides the write-only P property in A. ただし、キャストを使用して非表示の P プロパティにアクセスできることに注意してください。Note, however, that a cast can be used to access the hidden P property.

パブリックフィールドとは異なり、プロパティによって、オブジェクトの内部状態とそのパブリックインターフェイスが分離されます。Unlike public fields, properties provide a separation between an object's internal state and its public interface. 例を考えてみましょう。Consider the example:

class Label
{
    private int x, y;
    private string caption;

    public Label(int x, int y, string caption) {
        this.x = x;
        this.y = y;
        this.caption = caption;
    }

    public int X {
        get { return x; }
    }

    public int Y {
        get { return y; }
    }

    public Point Location {
        get { return new Point(x, y); }
    }

    public string Caption {
        get { return caption; }
    }
}

ここでは、Label クラスは、xyの2つの int フィールドを使用して、その場所を格納します。Here, the Label class uses two int fields, x and y, to store its location. この場所は、XY プロパティの両方と Point型の Location プロパティとして公開されています。The location is publicly exposed both as an X and a Y property and as a Location property of type Point. Labelの将来のバージョンでは、場所を Point として内部に格納する方が便利な場合があります。この変更は、クラスのパブリックインターフェイスに影響を与えることなく行うことができます。If, in a future version of Label, it becomes more convenient to store the location as a Point internally, the change can be made without affecting the public interface of the class:

class Label
{
    private Point location;
    private string caption;

    public Label(int x, int y, string caption) {
        this.location = new Point(x, y);
        this.caption = caption;
    }

    public int X {
        get { return location.x; }
    }

    public int Y {
        get { return location.y; }
    }

    public Point Location {
        get { return location; }
    }

    public string Caption {
        get { return caption; }
    }
}

public readonly フィールドではなく xy があったので、Label クラスに変更を加えることはできませんでした。Had x and y instead been public readonly fields, it would have been impossible to make such a change to the Label class.

プロパティを通じて状態を公開することは、フィールドを直接公開するよりも効率が低いとは限りません。Exposing state through properties is not necessarily any less efficient than exposing fields directly. 特に、プロパティが非仮想で、少量のコードのみが含まれている場合、実行環境では、アクセサーの呼び出しをアクセサーの実際のコードに置き換えることができます。In particular, when a property is non-virtual and contains only a small amount of code, the execution environment may replace calls to accessors with the actual code of the accessors. このプロセスはインライン展開と呼ばれ、フィールドアクセスと同じようにプロパティへのアクセスが可能になり、プロパティの柔軟性が向上します。This process is known as inlining, and it makes property access as efficient as field access, yet preserves the increased flexibility of properties.

get アクセサーを呼び出すことは、概念的にはフィールドの値を読み取ることと同じであるため、get アクセサーが監視可能な副作用を持つような不適切なプログラミングスタイルと見なされます。Since invoking a get accessor is conceptually equivalent to reading the value of a field, it is considered bad programming style for get accessors to have observable side-effects. この例では、In the example

class Counter
{
    private int next;

    public int Next {
        get { return next++; }
    }
}

Next プロパティの値は、プロパティが以前にアクセスされた回数によって異なります。the value of the Next property depends on the number of times the property has previously been accessed. したがって、プロパティにアクセスすると、監視可能な副作用が生成されます。プロパティは、代わりにメソッドとして実装する必要があります。Thus, accessing the property produces an observable side-effect, and the property should be implemented as a method instead.

get アクセサーに対する "副作用なし" の規則は、get アクセサーが常にフィールドに格納されている値を返すように記述する必要があるという意味ではありません。The "no side-effects" convention for get accessors doesn't mean that get accessors should always be written to simply return values stored in fields. 実際には、複数のフィールドにアクセスしたりメソッドを呼び出したりすることによって、多くの場合、get アクセサーがプロパティの値を計算します。Indeed, get accessors often compute the value of a property by accessing multiple fields or invoking methods. ただし、適切にデザインされた get アクセサーは、オブジェクトの状態の監視可能な変更の原因となるアクションを実行しません。However, a properly designed get accessor performs no actions that cause observable changes in the state of the object.

プロパティを使用して、リソースが最初に参照されるまで、リソースの初期化を遅延させることができます。Properties can be used to delay initialization of a resource until the moment it is first referenced. 例 :For example:

using System.IO;

public class Console
{
    private static TextReader reader;
    private static TextWriter writer;
    private static TextWriter error;

    public static TextReader In {
        get {
            if (reader == null) {
                reader = new StreamReader(Console.OpenStandardInput());
            }
            return reader;
        }
    }

    public static TextWriter Out {
        get {
            if (writer == null) {
                writer = new StreamWriter(Console.OpenStandardOutput());
            }
            return writer;
        }
    }

    public static TextWriter Error {
        get {
            if (error == null) {
                error = new StreamWriter(Console.OpenStandardError());
            }
            return error;
        }
    }
}

Console クラスには、標準入力、出力、およびエラーデバイスをそれぞれ表す、InOut、および Errorという3つのプロパティが含まれています。The Console class contains three properties, In, Out, and Error, that represent the standard input, output, and error devices, respectively. これらのメンバーをプロパティとして公開することによって、実際に使用されるまで、Console クラスは初期化を遅延させることができます。By exposing these members as properties, the Console class can delay their initialization until they are actually used. たとえば、最初に Out プロパティを参照したときに、次のようになります。For example, upon first referencing the Out property, as in

Console.Out.WriteLine("hello, world");

出力デバイスの基になる TextWriter が作成されます。the underlying TextWriter for the output device is created. ただし、アプリケーションが In プロパティと Error プロパティを参照していない場合、それらのデバイスのオブジェクトは作成されません。But if the application makes no reference to the In and Error properties, then no objects are created for those devices.

自動的に実装されたプロパティAutomatically implemented properties

自動的に実装されるプロパティ (または short の自動プロパティ) は、セミコロン専用のアクセサー本体を持つ非抽象非 extern プロパティです。An automatically implemented property (or auto-property for short), is a non-abstract non-extern property with semicolon-only accessor bodies. 自動プロパティには get アクセサーが必要であり、オプションで set アクセサーを持つことができます。Auto-properties must have a get accessor and can optionally have a set accessor.

プロパティが自動的に実装されるプロパティとして指定されている場合は、非表示のバッキングフィールドがプロパティで自動的に使用できるようになります。アクセサーは、そのバッキングフィールドに対して読み取りおよび書き込みを行うために実装されます。When a property is specified as an automatically implemented property, a hidden backing field is automatically available for the property, and the accessors are implemented to read from and write to that backing field. 自動プロパティに set アクセサーがない場合、バッキングフィールドは readonly (読み取り専用フィールド) と見なされます。If the auto-property has no set accessor, the backing field is considered readonly (Readonly fields). readonly フィールドと同様に、getter のみの自動プロパティも、外側のクラスのコンストラクターの本体でに割り当てることができます。Just like a readonly field, a getter-only auto-property can also be assigned to in the body of a constructor of the enclosing class. この割り当ては、プロパティの readonly バッキングフィールドに直接割り当てられます。Such an assignment assigns directly to the readonly backing field of the property.

自動プロパティには、必要に応じて、 variable_initializer (変数初期化子) としてバッキングフィールドに直接適用されるproperty_initializerを含めることができます。An auto-property may optionally have a property_initializer, which is applied directly to the backing field as a variable_initializer (Variable initializers).

次のような例です。The following example:

public class Point {
    public int X { get; set; } = 0;
    public int Y { get; set; } = 0;
}

は、次の宣言と同じです。is equivalent to the following declaration:

public class Point {
    private int __x = 0;
    private int __y = 0;
    public int X { get { return __x; } set { __x = value; } }
    public int Y { get { return __y; } set { __y = value; } }
}

次のような例です。The following example:

public class ReadOnlyPoint
{
    public int X { get; }
    public int Y { get; }
    public ReadOnlyPoint(int x, int y) { X = x; Y = y; }
}

は、次の宣言と同じです。is equivalent to the following declaration:

public class ReadOnlyPoint
{
    private readonly int __x;
    private readonly int __y;
    public int X { get { return __x; } }
    public int Y { get { return __y; } }
    public ReadOnlyPoint(int x, int y) { __x = x; __y = y; }
}

読み取り専用フィールドへの割り当ては、コンストラクター内で行われるため、有効です。Notice that the assignments to the readonly field are legal, because they occur within the constructor.

ユーザー補助Accessibility

アクセサーにaccessor_modifierがある場合、アクセサーのアクセシビリティドメイン (アクセシビリティドメイン) は、 accessor_modifierの宣言されたアクセシビリティを使用して決定されます。If an accessor has an accessor_modifier, the accessibility domain (Accessibility domains) of the accessor is determined using the declared accessibility of the accessor_modifier. アクセサーにaccessor_modifierがない場合、アクセサーのアクセシビリティドメインは、プロパティまたはインデクサーの宣言されたアクセシビリティから決まります。If an accessor does not have an accessor_modifier, the accessibility domain of the accessor is determined from the declared accessibility of the property or indexer.

Accessor_modifierが存在しても、メンバー参照 (演算子) やオーバーロードの解決 (オーバーロードの解決) には影響しません。The presence of an accessor_modifier never affects member lookup (Operators) or overload resolution (Overload resolution). プロパティまたはインデクサーの修飾子は、アクセスのコンテキストに関係なく、バインド先のプロパティまたはインデクサーを常に決定します。The modifiers on the property or indexer always determine which property or indexer is bound to, regardless of the context of the access.

特定のプロパティまたはインデクサーが選択されると、その使用法が有効かどうかを判断するために、関連する特定のアクセサーのアクセシビリティドメインが使用されます。Once a particular property or indexer has been selected, the accessibility domains of the specific accessors involved are used to determine if that usage is valid:

  • 使用法が値 (式の値) である場合は、get アクセサーが存在し、アクセス可能である必要があります。If the usage is as a value (Values of expressions), the get accessor must exist and be accessible.
  • 単純な代入 (単純な代入) の対象として使用する場合は、set アクセサーが存在し、アクセス可能である必要があります。If the usage is as the target of a simple assignment (Simple assignment), the set accessor must exist and be accessible.
  • 使用法が複合代入 (複合代入) のターゲットである場合、または ++ または -- 演算子 (関数メンバー.9、呼び出し式) のターゲットとして使用されている場合は、get アクセサーと set アクセサーの両方が存在し、アクセス可能である必要があります。If the usage is as the target of compound assignment (Compound assignment), or as the target of the ++ or -- operators (Function members.9, Invocation expressions), both the get accessors and the set accessor must exist and be accessible.

次の例では、プロパティ A.Text は、set アクセサーのみが呼び出されているコンテキストでも、プロパティ B.Textによって非表示になります。In the following example, the property A.Text is hidden by the property B.Text, even in contexts where only the set accessor is called. これに対し、プロパティ B.Count はクラス Mにアクセスできないため、代わりにアクセス可能なプロパティ A.Count が使用されます。In contrast, the property B.Count is not accessible to class M, so the accessible property A.Count is used instead.

class A
{
    public string Text {
        get { return "hello"; }
        set { }
    }

    public int Count {
        get { return 5; }
        set { }
    }
}

class B: A
{
    private string text = "goodbye"; 
    private int count = 0;

    new public string Text {
        get { return text; }
        protected set { text = value; }
    }

    new protected int Count { 
        get { return count; }
        set { count = value; }
    }
}

class M
{
    static void Main() {
        B b = new B();
        b.Count = 12;             // Calls A.Count set accessor
        int i = b.Count;          // Calls A.Count get accessor
        b.Text = "howdy";         // Error, B.Text set accessor not accessible
        string s = b.Text;        // Calls B.Text get accessor
    }
}

インターフェイスを実装するために使用されるアクセサーには、 accessor_modifierがない可能性があります。An accessor that is used to implement an interface may not have an accessor_modifier. インターフェイスを実装するために使用されるアクセサーが1つだけの場合、もう一方のアクセサーはaccessor_modifierを使用して宣言できます。If only one accessor is used to implement an interface, the other accessor may be declared with an accessor_modifier:

public interface I
{
    string Prop { get; }
}

public class C: I
{
    public string Prop {
        get { return "April"; }       // Must not have a modifier here
        internal set {...}            // Ok, because I.Prop has no set accessor
    }
}

仮想、シール、オーバーライド、および抽象プロパティアクセサーVirtual, sealed, override, and abstract property accessors

プロパティの宣言 virtual は、プロパティのアクセサーが仮想であることを指定します。A virtual property declaration specifies that the accessors of the property are virtual. virtual 修飾子は、読み取り/書き込みプロパティの両方のアクセサーに適用されます。読み取り/書き込みプロパティの1つのアクセサーだけを仮想にすることはできません。The virtual modifier applies to both accessors of a read-write property—it is not possible for only one accessor of a read-write property to be virtual.

abstract プロパティの宣言では、プロパティのアクセサーが仮想であることを指定しますが、アクセサーの実際の実装は提供しません。An abstract property declaration specifies that the accessors of the property are virtual, but does not provide an actual implementation of the accessors. 代わりに、抽象でない派生クラスは、プロパティをオーバーライドすることによって、アクセサーの独自の実装を提供する必要があります。Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the property. 抽象プロパティ宣言のアクセサーは実際の実装を提供しないため、 accessor_bodyは単にセミコロンで構成されます。Because an accessor for an abstract property declaration provides no actual implementation, its accessor_body simply consists of a semicolon.

abstract 修飾子と override 修飾子の両方を含むプロパティ宣言では、プロパティが abstract であり、基本プロパティがオーバーライドされることを指定します。A property declaration that includes both the abstract and override modifiers specifies that the property is abstract and overrides a base property. このようなプロパティのアクセサーも抽象型です。The accessors of such a property are also abstract.

抽象プロパティ宣言は、抽象クラス (抽象クラス) でのみ許可されます。継承された仮想プロパティのアクセサーは、override ディレクティブを指定するプロパティ宣言を含めることによって、派生クラスでオーバーライドできます。Abstract property declarations are only permitted in abstract classes (Abstract classes).The accessors of an inherited virtual property can be overridden in a derived class by including a property declaration that specifies an override directive. これは、オーバーライドするプロパティの宣言と呼ばれます。This is known as an overriding property declaration. オーバーライドするプロパティの宣言で、新しいプロパティが宣言されていません。An overriding property declaration does not declare a new property. 代わりに、既存の仮想プロパティのアクセサーの実装を単に特殊化します。Instead, it simply specializes the implementations of the accessors of an existing virtual property.

オーバーライドするプロパティの宣言では、継承されたプロパティとまったく同じアクセシビリティ修飾子、型、および名前を指定する必要があります。An overriding property declaration must specify the exact same accessibility modifiers, type, and name as the inherited property. 継承されたプロパティにアクセサーが1つしかない場合 (つまり、継承されたプロパティが読み取り専用または書き込み専用の場合)、オーバーライドする側のプロパティにはそのアクセサーだけを含める必要があります。If the inherited property has only a single accessor (i.e., if the inherited property is read-only or write-only), the overriding property must include only that accessor. 継承されたプロパティに両方のアクセサーが含まれている場合 (つまり、継承されたプロパティが読み取り/書き込みの場合)、オーバーライドする側のプロパティには、1つのアクセサーまたは両方のアクセサーを含めることができます。If the inherited property includes both accessors (i.e., if the inherited property is read-write), the overriding property can include either a single accessor or both accessors.

オーバーライドするプロパティの宣言には、sealed 修飾子を含めることができます。An overriding property declaration may include the sealed modifier. この修飾子を使用すると、派生クラスでプロパティをさらにオーバーライドできなくなります。Use of this modifier prevents a derived class from further overriding the property. シールされたプロパティのアクセサーもシールされます。The accessors of a sealed property are also sealed.

宣言と呼び出しの構文の違いを除けば、virtual、sealed、override、および abstract の各アクセサーは、仮想、シール、オーバーライド、抽象メソッドとまったく同じように動作します。Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. 具体的には、「仮想メソッド」、 「オーバーライドメソッド」、「シールメソッド」、および「抽象メソッド」で説明されている規則は、アクセサーが対応する形式のメソッドである場合と同様に適用されます。Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form:

  • get アクセサーは、プロパティの型の戻り値と、それを含むプロパティと同じ修飾子を持つパラメーターなしのメソッドに対応します。A get accessor corresponds to a parameterless method with a return value of the property type and the same modifiers as the containing property.
  • set アクセサーは、プロパティ型の単一の値パラメーター、void の戻り値の型、および格納しているプロパティと同じ修飾子を持つメソッドに対応します。A set accessor corresponds to a method with a single value parameter of the property type, a void return type, and the same modifiers as the containing property.

この例では、In the example

abstract class A
{
    int y;

    public virtual int X {
        get { return 0; }
    }

    public virtual int Y {
        get { return y; }
        set { y = value; }
    }

    public abstract int Z { get; set; }
}

X は仮想読み取り専用プロパティ、Y は仮想読み取り/書き込みプロパティ、Z は抽象読み取り/書き込みプロパティです。X is a virtual read-only property, Y is a virtual read-write property, and Z is an abstract read-write property. Z は抽象であるため、含んでいるクラス A も abstract として宣言する必要があります。Because Z is abstract, the containing class A must also be declared abstract.

A から派生するクラスを次に示します。A class that derives from A is show below:

class B: A
{
    int z;

    public override int X {
        get { return base.X + 1; }
    }

    public override int Y {
        set { base.Y = value < 0? 0: value; }
    }

    public override int Z {
        get { return z; }
        set { z = value; }
    }
}

ここでは、XY、および Z の宣言は、プロパティ宣言をオーバーライドしています。Here, the declarations of X, Y, and Z are overriding property declarations. 各プロパティ宣言は、対応する継承されたプロパティのアクセシビリティ修飾子、型、および名前と完全に一致します。Each property declaration exactly matches the accessibility modifiers, type, and name of the corresponding inherited property. Xget アクセサーと Yset アクセサーは、base キーワードを使用して、継承されたアクセサーにアクセスします。The get accessor of X and the set accessor of Y use the base keyword to access the inherited accessors. Z の宣言は、両方の抽象アクセサーをオーバーライドします。したがって、Bには未処理の抽象関数メンバーはなく、B は非抽象クラスにすることが許可されています。The declaration of Z overrides both abstract accessors—thus, there are no outstanding abstract function members in B, and B is permitted to be a non-abstract class.

プロパティが overrideとして宣言されている場合、オーバーライドされたアクセサーには、オーバーライドする側のコードからアクセスできる必要があります。When a property is declared as an override, any overridden accessors must be accessible to the overriding code. さらに、プロパティまたはインデクサー自体とアクセサーの両方について宣言されたアクセシビリティは、オーバーライドされるメンバーとアクセサーのアクセシビリティと一致する必要があります。In addition, the declared accessibility of both the property or indexer itself, and of the accessors, must match that of the overridden member and accessors. 例 :For example:

public class B
{
    public virtual int P {
        protected set {...}
        get {...}
    }
}

public class D: B
{
    public override int P {
        protected set {...}            // Must specify protected here
        get {...}                      // Must not have a modifier here
    }
}

イベントEvents

イベントは、オブジェクトまたはクラスが通知を提供できるようにするメンバーです。An event is a member that enables an object or class to provide notifications. クライアントは、イベントハンドラーを指定することによって、イベントの実行可能コードを添付できます。Clients can attach executable code for events by supplying event handlers.

イベントはevent_declarations を使用して宣言されます。Events are declared using event_declarations:

event_declaration
    : attributes? event_modifier* 'event' type variable_declarators ';'
    | attributes? event_modifier* 'event' type member_name '{' event_accessor_declarations '}'
    ;

event_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'static'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | event_modifier_unsafe
    ;

event_accessor_declarations
    : add_accessor_declaration remove_accessor_declaration
    | remove_accessor_declaration add_accessor_declaration
    ;

add_accessor_declaration
    : attributes? 'add' block
    ;

remove_accessor_declaration
    : attributes? 'remove' block
    ;

Event_declarationには、属性(属性) のセットと、4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせ、new (新しい修飾子)、static (静的メソッドとインスタンスメソッド)、virtual (仮想メソッド)、override (オーバーライドメソッド)、(シールメソッド)、sealed (抽象メソッド)、および abstract (外部メソッド) 修飾子を含めることができます。externAn event_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), static (Static and instance methods), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

イベント宣言には、修飾子の有効な組み合わせに関して、メソッド宣言 (メソッド) と同じ規則が適用されます。Event declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers.

イベント宣言のは、 delegate_type (参照型) である必要があります。また、 delegate_typeは、少なくともイベント自体 (アクセシビリティの制約) と同様にアクセス可能である必要があります。The type of an event declaration must be a delegate_type (Reference types), and that delegate_type must be at least as accessible as the event itself (Accessibility constraints).

イベント宣言には、 event_accessor_declarationsを含めることができます。An event declaration may include event_accessor_declarations. ただし、非 extern の非抽象イベントの場合は、コンパイラによって自動的に提供されます (フィールドに似たイベント)。extern イベントの場合、アクセサーは外部に提供されます。However, if it does not, for non-extern, non-abstract events, the compiler supplies them automatically (Field-like events); for extern events, the accessors are provided externally.

Event_accessor_declarationsを省略するイベント宣言は、1つ以上のイベント ( variable_declaratorのそれぞれに1つ) を定義します。An event declaration that omits event_accessor_declarations defines one or more events—one for each of the variable_declarators. 属性と修飾子は、このようなevent_declarationによって宣言されたすべてのメンバーに適用されます。The attributes and modifiers apply to all of the members declared by such an event_declaration.

Event_declarationabstract 修飾子と中かっこで区切られたevent_accessor_declarationsの両方を含めると、コンパイル時にエラーが発生します。It is a compile-time error for an event_declaration to include both the abstract modifier and brace-delimited event_accessor_declarations.

イベント宣言に extern 修飾子が含まれている場合、イベントは外部イベントと呼ばれます。When an event declaration includes an extern modifier, the event is said to be an external event. 外部イベント宣言は実際の実装を提供しないため、extern 修飾子とevent_accessor_declarationsの両方を含めることはできません。Because an external event declaration provides no actual implementation, it is an error for it to include both the extern modifier and event_accessor_declarations.

abstract または external 修飾子を持つイベント宣言のvariable_declaratorvariable_initializerを含むようにすると、コンパイル時にエラーが発生します。It is a compile-time error for a variable_declarator of an event declaration with an abstract or external modifier to include a variable_initializer.

イベントは、+= 演算子と -= 演算子 (イベント割り当て) の左側のオペランドとして使用できます。An event can be used as the left-hand operand of the += and -= operators (Event assignment). これらの演算子は、イベントからイベントハンドラーを削除するために、またはイベントからイベントハンドラーを削除するために、それぞれ使用されます。また、イベントのアクセス修飾子は、そのような操作が許可されているコンテキストを制御します。These operators are used, respectively, to attach event handlers to or to remove event handlers from an event, and the access modifiers of the event control the contexts in which such operations are permitted.

+=-= は、イベントを宣言する型以外のイベントで許可される唯一の操作であるため、外部コードはイベントのハンドラーを追加および削除できますが、それ以外のイベントハンドラーの一覧を取得または変更することはできません。Since += and -= are the only operations that are permitted on an event outside the type that declares the event, external code can add and remove handlers for an event, but cannot in any other way obtain or modify the underlying list of event handlers.

x += y または x -= yの形式の操作では、x がイベントであり、xの宣言を含む型の外で参照が行われた場合、演算の結果には void 型 (xの型ではなく、代入後の x の値) が含まれます。In an operation of the form x += y or x -= y, when x is an event and the reference takes place outside the type that contains the declaration of x, the result of the operation has type void (as opposed to having the type of x, with the value of x after the assignment). この規則は、外部コードがイベントの基になるデリゲートを間接的に調べることを禁止します。This rule prohibits external code from indirectly examining the underlying delegate of an event.

次の例は、イベントハンドラーが Button クラスのインスタンスにアタッチされる方法を示しています。The following example shows how event handlers are attached to instances of the Button class:

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;
}

public class LoginDialog: Form
{
    Button OkButton;
    Button CancelButton;

    public LoginDialog() {
        OkButton = new Button(...);
        OkButton.Click += new EventHandler(OkButtonClick);
        CancelButton = new Button(...);
        CancelButton.Click += new EventHandler(CancelButtonClick);
    }

    void OkButtonClick(object sender, EventArgs e) {
        // Handle OkButton.Click event
    }

    void CancelButtonClick(object sender, EventArgs e) {
        // Handle CancelButton.Click event
    }
}

ここでは、LoginDialog インスタンスコンストラクターが2つの Button インスタンスを作成し、イベントハンドラーを Click イベントにアタッチします。Here, the LoginDialog instance constructor creates two Button instances and attaches event handlers to the Click events.

フィールドに似たイベントField-like events

イベントの宣言を含むクラスまたは構造体のプログラムテキスト内では、フィールドのように特定のイベントを使用できます。Within the program text of the class or struct that contains the declaration of an event, certain events can be used like fields. このように使用するには、イベントを abstract または externしてはならず、 event_accessor_declarationsを明示的に含めることはできません。To be used in this way, an event must not be abstract or extern, and must not explicitly include event_accessor_declarations. このようなイベントは、フィールドを許可する任意のコンテキストで使用できます。Such an event can be used in any context that permits a field. フィールドには、イベントに追加されたイベントハンドラーのリストを参照するデリゲート (デリゲート) が含まれています。The field contains a delegate (Delegates) which refers to the list of event handlers that have been added to the event. イベントハンドラーが追加されていない場合、フィールドには nullが含まれます。If no event handlers have been added, the field contains null.

この例では、In the example

public delegate void EventHandler(object sender, EventArgs e);

public class Button: Control
{
    public event EventHandler Click;

    protected void OnClick(EventArgs e) {
        if (Click != null) Click(this, e);
    }

    public void Reset() {
        Click = null;
    }
}

Click は、Button クラス内のフィールドとして使用されます。Click is used as a field within the Button class. この例で示すように、フィールドは、デリゲート呼び出し式で検査、変更、および使用できます。As the example demonstrates, the field can be examined, modified, and used in delegate invocation expressions. Button クラスの OnClick メソッドは、Click イベントを発生させます。The OnClick method in the Button class "raises" the Click event. イベントを発生させるという概念は、イベントによって表されるデリゲートの呼び出しとまったく同じです。したがって、イベントを発生させるための特殊な言語コンストラクトはありません。The notion of raising an event is precisely equivalent to invoking the delegate represented by the event—thus, there are no special language constructs for raising events. デリゲート呼び出しの前に、デリゲートが null でないことを確認するチェックが付いていることに注意してください。Note that the delegate invocation is preceded by a check that ensures the delegate is non-null.

Button クラスの宣言の外側では、Click メンバーは、+= および -= 演算子の左側でのみ使用できます。Outside the declaration of the Button class, the Click member can only be used on the left-hand side of the += and -= operators, as in

b.Click += new EventHandler(...);

デリゲートを Click イベントの呼び出しリストに追加します。which appends a delegate to the invocation list of the Click event, and

b.Click -= new EventHandler(...);

Click イベントの呼び出しリストからデリゲートを削除します。which removes a delegate from the invocation list of the Click event.

フィールドに似たイベントをコンパイルすると、コンパイラは、デリゲートを保持するためのストレージを自動的に作成し、デリゲートフィールドに対してイベントハンドラーを追加または削除するイベントのアクセサーを作成します。When compiling a field-like event, the compiler automatically creates storage to hold the delegate, and creates accessors for the event that add or remove event handlers to the delegate field. 追加操作と削除操作は、スレッドセーフであり、インスタンスイベントの格納オブジェクトに対してロック (lock ステートメント) を保持しているとき、または静的イベントの型オブジェクト (匿名オブジェクト作成式) に対して実行する必要があります (ただし、必須ではありません)。The addition and removal operations are thread safe, and may (but are not required to) be done while holding the lock (The lock statement) on the containing object for an instance event, or the type object (Anonymous object creation expressions) for a static event.

したがって、次のような形式のインスタンスイベント宣言があります。Thus, an instance event declaration of the form:

class X
{
    public event D Ev;
}

は、次のものに相当するものにコンパイルされます。will be compiled to something equivalent to:

class X
{
    private D __Ev;  // field to hold the delegate

    public event D Ev {
        add {
            /* add the delegate in a thread safe way */
        }

        remove {
            /* remove the delegate in a thread safe way */
        }
    }
}

クラス X内では、+= および -= 演算子の左側にある Ev への参照によって、add アクセサーと remove アクセサーが呼び出されます。Within the class X, references to Ev on the left-hand side of the += and -= operators cause the add and remove accessors to be invoked. Ev へのその他のすべての参照は、非表示フィールド __Ev (メンバーアクセス) を参照するようにコンパイルされます。All other references to Ev are compiled to reference the hidden field __Ev instead (Member access). "__Ev" という名前は任意です。隠しフィールドには、任意の名前を付けることも、名前をまったく指定しないこともできます。The name "__Ev" is arbitrary; the hidden field could have any name or no name at all.

イベント アクセサーEvent accessors

イベント宣言は、通常、上記の Button の例のように、 event_accessor_declarationsを省略します。Event declarations typically omit event_accessor_declarations, as in the Button example above. これを行う1つの状況として、イベントごとに1つのフィールドのストレージコストが許容されない場合が挙げられます。One situation for doing so involves the case in which the storage cost of one field per event is not acceptable. このような場合、クラスにはevent_accessor_declarationsを追加し、イベントハンドラーのリストを格納するためのプライベート機構を使用できます。In such cases, a class can include event_accessor_declarations and use a private mechanism for storing the list of event handlers.

イベントのevent_accessor_declarationsでは、イベントハンドラーの追加と削除に関連付けられた実行可能なステートメントを指定します。The event_accessor_declarations of an event specify the executable statements associated with adding and removing event handlers.

アクセサー宣言は、 add_accessor_declarationremove_accessor_declarationで構成されます。The accessor declarations consist of an add_accessor_declaration and a remove_accessor_declaration. 各アクセサー宣言は add または remove の後にブロックが続くトークンで構成されます。Each accessor declaration consists of the token add or remove followed by a block. Add_accessor_declarationに関連付けられたブロックは、イベントハンドラーが追加されたときに実行するステートメントを指定します。また、 remove_accessor_declarationに関連付けられているブロックには、イベントハンドラーが削除されたときに実行するステートメントを指定します。The block associated with an add_accessor_declaration specifies the statements to execute when an event handler is added, and the block associated with a remove_accessor_declaration specifies the statements to execute when an event handler is removed.

add_accessor_declarationremove_accessor_declarationは、イベントの種類の単一の値パラメーターと void の戻り値の型を持つメソッドに対応します。Each add_accessor_declaration and remove_accessor_declaration corresponds to a method with a single value parameter of the event type and a void return type. イベントアクセサーの暗黙のパラメーターには valueという名前が付けられます。The implicit parameter of an event accessor is named value. イベントの割り当てでイベントが使用される場合は、適切なイベントアクセサーが使用されます。When an event is used in an event assignment, the appropriate event accessor is used. 具体的には、代入演算子が += 場合、add アクセサーが使用され、代入演算子が -= 場合は、remove アクセサーが使用されます。Specifically, if the assignment operator is += then the add accessor is used, and if the assignment operator is -= then the remove accessor is used. どちらの場合も、代入演算子の右側のオペランドは、イベントアクセサーの引数として使用されます。In either case, the right-hand operand of the assignment operator is used as the argument to the event accessor. Add_accessor_declarationまたはremove_accessor_declarationのブロックは、「メソッド本体」で説明されている void メソッドの規則に準拠している必要があります。The block of an add_accessor_declaration or a remove_accessor_declaration must conform to the rules for void methods described in Method body. 特に、このようなブロック内の return ステートメントでは、式を指定することはできません。In particular, return statements in such a block are not permitted to specify an expression.

イベントアクセサーには valueという名前のパラメーターが暗黙的に含まれるため、イベントアクセサーで宣言されたローカル変数または定数がその名前を持つようにすると、コンパイル時エラーになります。Since an event accessor implicitly has a parameter named value, it is a compile-time error for a local variable or constant declared in an event accessor to have that name.

この例では、In the example

class Control: Component
{
    // Unique keys for events
    static readonly object mouseDownEventKey = new object();
    static readonly object mouseUpEventKey = new object();

    // Return event handler associated with key
    protected Delegate GetEventHandler(object key) {...}

    // Add event handler associated with key
    protected void AddEventHandler(object key, Delegate handler) {...}

    // Remove event handler associated with key
    protected void RemoveEventHandler(object key, Delegate handler) {...}

    // MouseDown event
    public event MouseEventHandler MouseDown {
        add { AddEventHandler(mouseDownEventKey, value); }
        remove { RemoveEventHandler(mouseDownEventKey, value); }
    }

    // MouseUp event
    public event MouseEventHandler MouseUp {
        add { AddEventHandler(mouseUpEventKey, value); }
        remove { RemoveEventHandler(mouseUpEventKey, value); }
    }

    // Invoke the MouseUp event
    protected void OnMouseUp(MouseEventArgs args) {
        MouseEventHandler handler; 
        handler = (MouseEventHandler)GetEventHandler(mouseUpEventKey);
        if (handler != null)
            handler(this, args);
    }
}

Control クラスは、イベントの内部ストレージ機構を実装します。the Control class implements an internal storage mechanism for events. AddEventHandler メソッドはデリゲート値をキーに関連付け、GetEventHandler メソッドは、現在キーに関連付けられているデリゲートを返します。また、RemoveEventHandler メソッドは、指定されたイベントのイベントハンドラーとしてデリゲートを削除します。The AddEventHandler method associates a delegate value with a key, the GetEventHandler method returns the delegate currently associated with a key, and the RemoveEventHandler method removes a delegate as an event handler for the specified event. たとえば、基になるストレージメカニズムは、null デリゲート値をキーに関連付けてもコストが発生しないように設計されているため、未処理のイベントはストレージを使用しません。Presumably, the underlying storage mechanism is designed such that there is no cost for associating a null delegate value with a key, and thus unhandled events consume no storage.

静的イベントとインスタンスイベントStatic and instance events

イベント宣言に static 修飾子が含まれている場合、イベントは静的イベントと呼ばれます。When an event declaration includes a static modifier, the event is said to be a static event. static 修飾子が存在しない場合、イベントはインスタンスイベントと呼ばれます。When no static modifier is present, the event is said to be an instance event.

静的イベントは特定のインスタンスに関連付けられておらず、静的イベントのアクセサーで this を参照するコンパイル時エラーです。A static event is not associated with a specific instance, and it is a compile-time error to refer to this in the accessors of a static event.

インスタンスイベントは、クラスの特定のインスタンスに関連付けられます。このインスタンスには、そのイベントのアクセサーで this (このアクセス) としてアクセスできます。An instance event is associated with a given instance of a class, and this instance can be accessed as this (This access) in the accessors of that event.

フォーム E.Mmember_access (メンバーアクセス) でイベントが参照されている場合、M が静的イベントである場合、EMを含む型を示す必要があり、M がインスタンスイベントの場合、E は Mを含む型のインスタンスを示す必要があります。When an event is referenced in a member_access (Member access) of the form E.M, if M is a static event, E must denote a type containing M, and if M is an instance event, E must denote an instance of a type containing M.

静的メンバーとインスタンスメンバーの違いについては、「静的メンバーとインスタンスメンバー」で詳しく説明します。The differences between static and instance members are discussed further in Static and instance members.

仮想、シール、オーバーライド、および抽象イベントアクセサーVirtual, sealed, override, and abstract event accessors

virtual イベント宣言は、そのイベントのアクセサーが仮想であることを指定します。A virtual event declaration specifies that the accessors of that event are virtual. virtual 修飾子は、イベントの両方のアクセサーに適用されます。The virtual modifier applies to both accessors of an event.

abstract イベント宣言は、イベントのアクセサーが仮想であることを指定しますが、アクセサーの実際の実装は提供しません。An abstract event declaration specifies that the accessors of the event are virtual, but does not provide an actual implementation of the accessors. 代わりに、非抽象派生クラスは、イベントをオーバーライドすることによって、アクセサーの独自の実装を提供する必要があります。Instead, non-abstract derived classes are required to provide their own implementation for the accessors by overriding the event. 抽象イベント宣言は実際の実装を提供しないため、中かっこで区切られたevent_accessor_declarationsを提供することはできません。Because an abstract event declaration provides no actual implementation, it cannot provide brace-delimited event_accessor_declarations.

abstractoverride の両方の修飾子を含むイベント宣言は、イベントが抽象であり、基本イベントをオーバーライドすることを指定します。An event declaration that includes both the abstract and override modifiers specifies that the event is abstract and overrides a base event. このようなイベントのアクセサーも抽象的なものです。The accessors of such an event are also abstract.

抽象イベント宣言は、抽象クラス (抽象クラス) でのみ許可されます。Abstract event declarations are only permitted in abstract classes (Abstract classes).

継承された仮想イベントのアクセサーは、override 修飾子を指定するイベント宣言を含めることによって、派生クラスでオーバーライドできます。The accessors of an inherited virtual event can be overridden in a derived class by including an event declaration that specifies an override modifier. これは、オーバーライドするイベント宣言と呼ばれます。This is known as an overriding event declaration. オーバーライドするイベント宣言では、新しいイベントが宣言されていません。An overriding event declaration does not declare a new event. 代わりに、既存の仮想イベントのアクセサーの実装を単に特殊化します。Instead, it simply specializes the implementations of the accessors of an existing virtual event.

オーバーライドするイベント宣言では、オーバーライドされたイベントとまったく同じアクセシビリティ修飾子、型、および名前を指定する必要があります。An overriding event declaration must specify the exact same accessibility modifiers, type, and name as the overridden event.

オーバーライドするイベント宣言には、sealed 修飾子を含めることができます。An overriding event declaration may include the sealed modifier. この修飾子を使用すると、派生クラスでイベントをさらにオーバーライドできなくなります。Use of this modifier prevents a derived class from further overriding the event. シールされたイベントのアクセサーもシールされます。The accessors of a sealed event are also sealed.

オーバーライドするイベント宣言に new 修飾子を含めると、コンパイル時にエラーが発生します。It is a compile-time error for an overriding event declaration to include a new modifier.

宣言と呼び出しの構文の違いを除けば、virtual、sealed、override、および abstract の各アクセサーは、仮想、シール、オーバーライド、抽象メソッドとまったく同じように動作します。Except for differences in declaration and invocation syntax, virtual, sealed, override, and abstract accessors behave exactly like virtual, sealed, override and abstract methods. 具体的には、「仮想メソッド」、 「オーバーライドメソッド」、「シールメソッド」、および「抽象メソッド」で説明されている規則は、アクセサーが対応するフォームのメソッドである場合と同様に適用されます。Specifically, the rules described in Virtual methods, Override methods, Sealed methods, and Abstract methods apply as if accessors were methods of a corresponding form. 各アクセサーは、イベントの種類の単一の値パラメーター、void の戻り値の型、および含んでいるイベントと同じ修飾子を持つメソッドに対応します。Each accessor corresponds to a method with a single value parameter of the event type, a void return type, and the same modifiers as the containing event.

インデクサーIndexers

インデクサーは、配列と同じ方法でオブジェクトのインデックスを作成できるようにするメンバーです。An indexer is a member that enables an object to be indexed in the same way as an array. インデクサーはindexer_declarations を使用して宣言されます。Indexers are declared using indexer_declarations:

indexer_declaration
    : attributes? indexer_modifier* indexer_declarator indexer_body
    ;

indexer_modifier
    : 'new'
    | 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'virtual'
    | 'sealed'
    | 'override'
    | 'abstract'
    | 'extern'
    | indexer_modifier_unsafe
    ;

indexer_declarator
    : type 'this' '[' formal_parameter_list ']'
    | type interface_type '.' 'this' '[' formal_parameter_list ']'
    ;

indexer_body
    : '{' accessor_declarations '}' 
    | '=>' expression ';'
    ;

Indexer_declarationには、一連の属性(属性) と、4つのアクセス修飾子 (アクセス修飾子)、new (新しい修飾子)、virtual (仮想メソッド)、override (オーバーライドメソッド)、sealed (シールメソッド)、abstract (抽象メソッド)、および extern (外部メソッド) 修飾子の有効な組み合わせを含めることができます。An indexer_declaration may include a set of attributes (Attributes) and a valid combination of the four access modifiers (Access modifiers), the new (The new modifier), virtual (Virtual methods), override (Override methods), sealed (Sealed methods), abstract (Abstract methods), and extern (External methods) modifiers.

インデクサー宣言では、修飾子の有効な組み合わせに関して、メソッド宣言 (メソッド) と同じ規則が適用されます。一方、インデクサー宣言では static 修飾子は許可されないという例外があります。Indexer declarations are subject to the same rules as method declarations (Methods) with regard to valid combinations of modifiers, with the one exception being that the static modifier is not permitted on an indexer declaration.

修飾子 virtualoverride、および abstract は、1つの場合を除き、相互に排他的です。The modifiers virtual, override, and abstract are mutually exclusive except in one case. Abstract インデクサーが仮想1をオーバーライドできるように、abstract 修飾子と override 修飾子を一緒に使用することができます。The abstract and override modifiers may be used together so that an abstract indexer can override a virtual one.

インデクサー宣言のは、宣言によって導入されるインデクサーの要素の種類を指定します。The type of an indexer declaration specifies the element type of the indexer introduced by the declaration. インデクサーが明示的なインターフェイスメンバーの実装でない限り、の後にキーワード thisが続きます。Unless the indexer is an explicit interface member implementation, the type is followed by the keyword this. 明示的なインターフェイスメンバーの実装では、の後にinterface_type、"."、およびキーワード thisが続きます。For an explicit interface member implementation, the type is followed by an interface_type, a ".", and the keyword this. 他のメンバーとは異なり、インデクサーにはユーザー定義の名前がありません。Unlike other members, indexers do not have user-defined names.

Formal_parameter_listは、インデクサーのパラメーターを指定します。The formal_parameter_list specifies the parameters of the indexer. インデクサーの仮パラメーターリストは、メソッドのパラメーター (メソッドパラメーター) と対応しています。ただし、パラメーターを少なくとも1つ指定する必要があります。また、ref および out パラメーター修飾子は使用できません。The formal parameter list of an indexer corresponds to that of a method (Method parameters), except that at least one parameter must be specified, and that the ref and out parameter modifiers are not permitted.

インデクサーのformal_parameter_listで参照される各型は、少なくとも、インデクサー自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。The type of an indexer and each of the types referenced in the formal_parameter_list must be at least as accessible as the indexer itself (Accessibility constraints).

Indexer_bodyは、アクセサー本体または式の本体で構成されている場合があります。An indexer_body may either consist of an accessor body or an expression body. アクセサー本体で、 accessor_declarationsを "{" および "}" トークンで囲む必要がある場合は、プロパティのアクセサー (アクセサー) を宣言します。In an accessor body, accessor_declarations, which must be enclosed in "{" and "}" tokens, declare the accessors (Accessors) of the property. アクセサーは、プロパティの読み取りと書き込みに関連付けられた実行可能なステートメントを指定します。The accessors specify the executable statements associated with reading and writing the property.

"=>" の後に式 E が続く式本体と、セミコロンはステートメント本体 { get { return E; } }とまったく同じであり、そのため、getter の結果が1つの式で指定される getter のみのインデクサーを指定する場合にのみ使用できます。An expression body consisting of "=>" followed by an expression E and a semicolon is exactly equivalent to the statement body { get { return E; } }, and can therefore only be used to specify getter-only indexers where the result of the getter is given by a single expression.

インデクサー要素にアクセスするための構文は、配列要素の構文と同じですが、インデクサー要素は変数として分類されません。Even though the syntax for accessing an indexer element is the same as that for an array element, an indexer element is not classified as a variable. このため、インデクサー要素を ref または out 引数として渡すことはできません。Thus, it is not possible to pass an indexer element as a ref or out argument.

インデクサーの仮パラメーターリストでは、インデクサーの署名 (シグネチャとオーバーロード) を定義します。The formal parameter list of an indexer defines the signature (Signatures and overloading) of the indexer. 具体的には、インデクサーのシグネチャは、その仮パラメーターの数と型で構成されます。Specifically, the signature of an indexer consists of the number and types of its formal parameters. 仮パラメーターの要素の型と名前は、インデクサーのシグネチャの一部ではありません。The element type and names of the formal parameters are not part of an indexer's signature.

インデクサーのシグネチャは、同じクラスで宣言されている他のすべてのインデクサーのシグネチャと異なる必要があります。The signature of an indexer must differ from the signatures of all other indexers declared in the same class.

インデクサーとプロパティは概念とよく似ていますが、次の点が異なります。Indexers and properties are very similar in concept, but differ in the following ways:

  • プロパティは名前で識別されますが、インデクサーはそのシグネチャによって識別されます。A property is identified by its name, whereas an indexer is identified by its signature.
  • プロパティは、 simple_name (簡易名) またはmember_access (メンバーアクセス) を介してアクセスされます。一方、インデクサー要素はelement_access (インデクサーアクセス) を介してアクセスされます。A property is accessed through a simple_name (Simple names) or a member_access (Member access), whereas an indexer element is accessed through an element_access (Indexer access).
  • プロパティは static メンバーにすることができますが、インデクサーは常にインスタンスメンバーになります。A property can be a static member, whereas an indexer is always an instance member.
  • プロパティの get アクセサーは、パラメーターのないメソッドに対応します。一方、インデクサーの get アクセサーは、インデクサーと同じ仮パラメーターリストを持つメソッドに対応します。A get accessor of a property corresponds to a method with no parameters, whereas a get accessor of an indexer corresponds to a method with the same formal parameter list as the indexer.
  • プロパティの set アクセサーは、valueという名前の1つのパラメーターを持つメソッドに対応します。一方、インデクサーの set アクセサーは、インデクサーと同じ仮パラメーターリストと、valueという名前の追加パラメーターを持つメソッドに対応します。A set accessor of a property corresponds to a method with a single parameter named value, whereas a set accessor of an indexer corresponds to a method with the same formal parameter list as the indexer, plus an additional parameter named value.
  • インデクサーアクセサーがインデクサーパラメーターと同じ名前を持つローカル変数を宣言する場合、コンパイル時エラーになります。It is a compile-time error for an indexer accessor to declare a local variable with the same name as an indexer parameter.
  • オーバーライドするプロパティの宣言では、base.P構文を使用して、継承されたプロパティにアクセスします。 P はプロパティ名です。In an overriding property declaration, the inherited property is accessed using the syntax base.P, where P is the property name. オーバーライドするインデクサーの宣言では、base[E]構文を使用して、継承されたインデクサーにアクセスします。 E は、コンマで区切られた式のリストです。In an overriding indexer declaration, the inherited indexer is accessed using the syntax base[E], where E is a comma separated list of expressions.
  • "自動的に実装されたインデクサー" の概念はありません。There is no concept of an "automatically implemented indexer". セミコロン (;) 以外の非抽象インデクサーを使用すると、エラーになります。It is an error to have a non-abstract, non-external indexer with semicolon accessors.

これらの違いを除けば、アクセサー自動的に実装されるプロパティで定義されているすべての規則は、インデクサーアクセサーおよびプロパティアクセサーに適用されます。Aside from these differences, all rules defined in Accessors and Automatically implemented properties apply to indexer accessors as well as to property accessors.

インデクサー宣言に extern 修飾子が含まれている場合、インデクサーは外部インデクサーと呼ばれます。When an indexer declaration includes an extern modifier, the indexer is said to be an external indexer. 外部インデクサー宣言は実際の実装を提供しないため、各accessor_declarationsはセミコロンで構成されます。Because an external indexer declaration provides no actual implementation, each of its accessor_declarations consists of a semicolon.

次の例では、ビット配列内の個々のビットにアクセスするためのインデクサーを実装する BitArray クラスを宣言しています。The example below declares a BitArray class that implements an indexer for accessing the individual bits in the bit array.

using System;

class BitArray
{
    int[] bits;
    int length;

    public BitArray(int length) {
        if (length < 0) throw new ArgumentException();
        bits = new int[((length - 1) >> 5) + 1];
        this.length = length;
    }

    public int Length {
        get { return length; }
    }

    public bool this[int index] {
        get {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            return (bits[index >> 5] & 1 << index) != 0;
        }
        set {
            if (index < 0 || index >= length) {
                throw new IndexOutOfRangeException();
            }
            if (value) {
                bits[index >> 5] |= 1 << index;
            }
            else {
                bits[index >> 5] &= ~(1 << index);
            }
        }
    }
}

BitArray クラスのインスタンスは、対応する bool[] よりもかなり少ないメモリを消費します (前者の各値は、後者の1バイトではなく1ビットのみを占有するため)。ただし、bool[]と同じ操作を許可します。An instance of the BitArray class consumes substantially less memory than a corresponding bool[] (since each value of the former occupies only one bit instead of the latter's one byte), but it permits the same operations as a bool[].

次の CountPrimes クラスは、BitArray とクラシック "エラトステネス" アルゴリズムを使用して、1から指定された最大値までの primes 数を計算します。The following CountPrimes class uses a BitArray and the classical "sieve" algorithm to compute the number of primes between 1 and a given maximum:

class CountPrimes
{
    static int Count(int max) {
        BitArray flags = new BitArray(max + 1);
        int count = 1;
        for (int i = 2; i <= max; i++) {
            if (!flags[i]) {
                for (int j = i * 2; j <= max; j += i) flags[j] = true;
                count++;
            }
        }
        return count;
    }

    static void Main(string[] args) {
        int max = int.Parse(args[0]);
        int count = Count(max);
        Console.WriteLine("Found {0} primes between 1 and {1}", count, max);
    }
}

BitArray の要素にアクセスするための構文は、bool[]の場合とまったく同じであることに注意してください。Note that the syntax for accessing elements of the BitArray is precisely the same as for a bool[].

次の例は、2つのパラメーターを持つインデクサーを持つ 26 * 10 grid クラスを示しています。The following example shows a 26 * 10 grid class that has an indexer with two parameters. 最初のパラメーターは、A ~ Z の範囲の大文字または小文字にする必要があり、2番目のパラメーターは0-9 の範囲の整数である必要があります。The first parameter is required to be an upper- or lowercase letter in the range A-Z, and the second is required to be an integer in the range 0-9.

using System;

class Grid
{
    const int NumRows = 26;
    const int NumCols = 10;

    int[,] cells = new int[NumRows, NumCols];

    public int this[char c, int col] {
        get {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            return cells[c - 'A', col];
        }

        set {
            c = Char.ToUpper(c);
            if (c < 'A' || c > 'Z') {
                throw new ArgumentException();
            }
            if (col < 0 || col >= NumCols) {
                throw new IndexOutOfRangeException();
            }
            cells[c - 'A', col] = value;
        }
    }
}

インデクサーのオーバーロードIndexer overloading

インデクサーのオーバーロードの解決規則については、 「型の推定」を参照してください。The indexer overload resolution rules are described in Type inference.

演算子Operators

演算子は、クラスのインスタンスに適用できる式演算子の意味を定義するメンバーです。An operator is a member that defines the meaning of an expression operator that can be applied to instances of the class. 演算子はoperator_declarations を使用して宣言されます。Operators are declared using operator_declarations:

operator_declaration
    : attributes? operator_modifier+ operator_declarator operator_body
    ;

operator_modifier
    : 'public'
    | 'static'
    | 'extern'
    | operator_modifier_unsafe
    ;

operator_declarator
    : unary_operator_declarator
    | binary_operator_declarator
    | conversion_operator_declarator
    ;

unary_operator_declarator
    : type 'operator' overloadable_unary_operator '(' type identifier ')'
    ;

overloadable_unary_operator
    : '+' | '-' | '!' | '~' | '++' | '--' | 'true' | 'false'
    ;

binary_operator_declarator
    : type 'operator' overloadable_binary_operator '(' type identifier ',' type identifier ')'
    ;

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

conversion_operator_declarator
    : 'implicit' 'operator' type '(' type identifier ')'
    | 'explicit' 'operator' type '(' type identifier ')'
    ;

operator_body
    : block
    | '=>' expression ';'
    | ';'
    ;

オーバーロード可能な演算子には、単項演算子 (単項演算子)、二項演算子 (二項演算子)、および変換演算子 (変換演算子) の3つのカテゴリがあります。There are three categories of overloadable operators: Unary operators (Unary operators), binary operators (Binary operators), and conversion operators (Conversion operators).

Operator_bodyは、セミコロン、ステートメント本体、または式の本体です。The operator_body is either a semicolon, a statement body or an expression body. ステートメントの本体は、ブロックで構成されます。これは、演算子が呼び出されたときに実行するステートメントを指定します。A statement body consists of a block, which specifies the statements to execute when the operator is invoked. ブロックは、「メソッド本体」で説明されている値を返すメソッドの規則に準拠している必要があります。The block must conform to the rules for value-returning methods described in Method body. 式の本体は => で構成され、その後に式とセミコロンが続き、演算子が呼び出されたときに実行する1つの式を示します。An expression body consists of => followed by an expression and a semicolon, and denotes a single expression to perform when the operator is invoked.

extern 演算子の場合、 operator_bodyはセミコロンで構成されます。For extern operators, the operator_body consists simply of a semicolon. その他のすべての演算子では、 operator_bodyはブロック本体または式の本体です。For all other operators, the operator_body is either a block body or an expression body.

すべての演算子宣言には、次の規則が適用されます。The following rules apply to all operator declarations:

  • 演算子の宣言には、publicstatic 修飾子の両方を含める必要があります。An operator declaration must include both a public and a static modifier.
  • 演算子のパラメーターは、値パラメーター (値パラメーター) である必要があります。The parameter(s) of an operator must be value parameters (Value parameters). 演算子宣言で ref パラメーターまたは out パラメーターを指定する場合、コンパイル時エラーになります。It is a compile-time error for an operator declaration to specify ref or out parameters.
  • 演算子のシグネチャ (単項演算子二項演算子変換演算子) は、同じクラスで宣言されている他のすべての演算子のシグネチャとは異なる必要があります。The signature of an operator (Unary operators, Binary operators, Conversion operators) must differ from the signatures of all other operators declared in the same class.
  • 演算子宣言で参照されるすべての型は、少なくとも演算子自体 (アクセシビリティ制約) と同じようにアクセス可能である必要があります。All types referenced in an operator declaration must be at least as accessible as the operator itself (Accessibility constraints).
  • 同じ修飾子が演算子宣言で複数回出現する場合、エラーになります。It is an error for the same modifier to appear multiple times in an operator declaration.

各演算子カテゴリでは、次のセクションで説明するように、追加の制限が課せられます。Each operator category imposes additional restrictions, as described in the following sections.

他のメンバーと同様に、基底クラスで宣言された演算子は、派生クラスによって継承されます。Like other members, operators declared in a base class are inherited by derived classes. 演算子宣言は、演算子のシグネチャに参加するように宣言されているクラスまたは構造体を常に必要とするため、派生クラスで宣言された演算子が基底クラスで宣言された演算子を非表示にすることはできません。Because operator declarations always require the class or struct in which the operator is declared to participate in the signature of the operator, it is not possible for an operator declared in a derived class to hide an operator declared in a base class. したがって、演算子の宣言では、new 修飾子は不要であり、許可されません。Thus, the new modifier is never required, and therefore never permitted, in an operator declaration.

単項演算子と二項演算子の詳細については、「演算子」を参照してください。Additional information on unary and binary operators can be found in Operators.

変換演算子の追加情報については、「ユーザー定義変換」を参照してください。Additional information on conversion operators can be found in User-defined conversions.

単項演算子Unary operators

次の規則は単項演算子の宣言に適用されます。 T は、演算子宣言を含むクラスまたは構造体のインスタンス型を表します。The following rules apply to unary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • 単項 +-!、または ~ 演算子は、型 T または T? の1つのパラメーターを受け取る必要があり、任意の型を返すことができます。A unary +, -, !, or ~ operator must take a single parameter of type T or T? and can return any type.
  • 単項 ++ または -- 演算子は T または T? 型の1つのパラメーターを受け取る必要があり、同じ型またはそれから派生した型を返す必要があります。A unary ++ or -- operator must take a single parameter of type T or T? and must return that same type or a type derived from it.
  • 単項 true または false 演算子は、型 T または T? の1つのパラメーターを受け取る必要があり、型 boolを返す必要があります。A unary true or false operator must take a single parameter of type T or T? and must return type bool.

単項演算子のシグネチャは、演算子トークン (+-!~++--true、または false) と、単一の仮パラメーターの型で構成されます。The signature of a unary operator consists of the operator token (+, -, !, ~, ++, --, true, or false) and the type of the single formal parameter. 戻り値の型は単項演算子のシグネチャの一部ではなく、仮パラメーターの名前でもありません。The return type is not part of a unary operator's signature, nor is the name of the formal parameter.

true および false の単項演算子には、ペアごとの宣言が必要です。The true and false unary operators require pair-wise declaration. クラスでこれらの演算子のいずれかが宣言されていない場合、コンパイル時にエラーが発生します。A compile-time error occurs if a class declares one of these operators without also declaring the other. true 演算子と false 演算子については、ユーザー定義の条件付き論理演算子ブール式を参照してください。The true and false operators are described further in User-defined conditional logical operators and Boolean expressions.

次の例は、整数 vector クラスの operator ++ の実装とその後の使用法を示しています。The following example shows an implementation and subsequent usage of operator ++ for an integer vector class:

public class IntVector
{
    public IntVector(int length) {...}

    public int Length {...}                 // read-only property

    public int this[int index] {...}        // read-write indexer

    public static IntVector operator ++(IntVector iv) {
        IntVector temp = new IntVector(iv.Length);
        for (int i = 0; i < iv.Length; i++)
            temp[i] = iv[i] + 1;
        return temp;
    }
}

class Test
{
    static void Main() {
        IntVector iv1 = new IntVector(4);    // vector of 4 x 0
        IntVector iv2;

        iv2 = iv1++;    // iv2 contains 4 x 0, iv1 contains 4 x 1
        iv2 = ++iv1;    // iv2 contains 4 x 2, iv1 contains 4 x 2
    }
}

演算子メソッドが、オペランドに1を加算することによって生成される値を返す方法に注意してください。後置インクリメント演算子とデクリメント演算子 (後置インクリメント演算子およびデクリメント演算子) と同様、前置インクリメント演算子と前置デクリメント演算子 (前置インクリメント演算子およびデクリメント演算子) と同様です。Note how the operator method returns the value produced by adding 1 to the operand, just like the postfix increment and decrement operators (Postfix increment and decrement operators), and the prefix increment and decrement operators (Prefix increment and decrement operators). とはC++異なり、このメソッドでは、オペランドの値を直接変更する必要はありません。Unlike in C++, this method need not modify the value of its operand directly. 実際、オペランドの値を変更すると、後置インクリメント演算子の標準セマンティクスに違反することになります。In fact, modifying the operand value would violate the standard semantics of the postfix increment operator.

バイナリ演算子Binary operators

次の規則は、二項演算子の宣言に適用されます。ここで T は、演算子宣言を含むクラスまたは構造体のインスタンス型を表します。The following rules apply to binary operator declarations, where T denotes the instance type of the class or struct that contains the operator declaration:

  • 二項非シフト演算子は、2つのパラメーターを受け取る必要があります。少なくとも1つは型 T または T?である必要があり、任意の型を返すことができます。A binary non-shift operator must take two parameters, at least one of which must have type T or T?, and can return any type.
  • バイナリ << または >> 演算子は、2つのパラメーターを受け取る必要があります。1つ目のパラメーターの型は T または T? で、2番目のパラメーターの型は int または int?である必要があり、任意の型を返すことができます。A binary << or >> operator must take two parameters, the first of which must have type T or T? and the second of which must have type int or int?, and can return any type.

二項演算子の署名は、演算子トークン (+-*/%&|^<<>>==!=) と、2つの仮パラメーターの型で構成されますが、>``<``>=``<=The signature of a binary operator consists of the operator token (+, -, *, /, %, &, |, ^, <<, >>, ==, !=, >, <, >=, or <=) and the types of the two formal parameters. 戻り値の型と仮パラメーターの名前は、二項演算子のシグネチャの一部ではありません。The return type and the names of the formal parameters are not part of a binary operator's signature.

特定の二項演算子には、ペアごとの宣言が必要です。Certain binary operators require pair-wise declaration. ペアのいずれかの演算子を宣言する場合は、そのペアのもう一方の演算子の宣言が一致している必要があります。For every declaration of either operator of a pair, there must be a matching declaration of the other operator of the pair. 2つの演算子宣言は、同じ戻り値の型を持ち、各パラメーターの型が同じである場合に一致します。Two operator declarations match when they have the same return type and the same type for each parameter. 次の演算子では、ペアごとの宣言が必要です。The following operators require pair-wise declaration:

  • operator == および operator !=operator == and operator !=
  • operator > および operator <operator > and operator <
  • operator >= および operator <=operator >= and operator <=

変換演算子Conversion operators

変換演算子の宣言では、定義済みの暗黙的な変換と明示的な変換を補強する、ユーザー定義の変換(ユーザー定義の変換) が導入されます。A conversion operator declaration introduces a user-defined conversion (User-defined conversions) which augments the pre-defined implicit and explicit conversions.

implicit キーワードを含む変換演算子の宣言では、ユーザー定義の暗黙的な変換が導入されます。A conversion operator declaration that includes the implicit keyword introduces a user-defined implicit conversion. 暗黙の型変換は、関数メンバー呼び出し、キャスト式、代入など、さまざまな状況で発生する可能性があります。Implicit conversions can occur in a variety of situations, including function member invocations, cast expressions, and assignments. この詳細については、「暗黙的な変換」を参照してください。This is described further in Implicit conversions.

explicit キーワードを含む変換演算子の宣言では、ユーザー定義の明示的な変換が導入されます。A conversion operator declaration that includes the explicit keyword introduces a user-defined explicit conversion. 明示的な変換は、キャスト式で発生する可能性があり、明示的な変換で詳しく説明されています。Explicit conversions can occur in cast expressions, and are described further in Explicit conversions.

変換演算子は、変換演算子のパラメーター型で示される変換元の型を変換演算子の戻り値の型で指定されたターゲットの型に変換します。A conversion operator converts from a source type, indicated by the parameter type of the conversion operator, to a target type, indicated by the return type of the conversion operator.

指定されたソース型 S とターゲット型 Tの場合、S または T が null 許容型である場合は、S0T0 がその基になる型を参照するようにします。それ以外の場合、S0T0 はそれぞれ ST になります。For a given source type S and target type T, if S or T are nullable types, let S0 and T0 refer to their underlying types, otherwise S0 and T0 are equal to S and T respectively. クラスまたは構造体は、次のすべての条件を満たす場合にのみ、ソース S 型からターゲット T 型への変換を宣言することができます。A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true:

  • S0T0 の種類は異なります。S0 and T0 are different types.
  • S0 または T0 は、演算子の宣言が行われるクラスまたは構造体の型です。Either S0 or T0 is the class or struct type in which the operator declaration takes place.
  • S0T0interface_typeではありません。Neither S0 nor T0 is an interface_type.
  • ユーザー定義の変換を除外すると、S から T または T から Sへの変換は存在しません。Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.

これらの規則のために、S または T に関連付けられている型パラメーターは、他の型との継承関係がない一意の型と見なされます。これらの型パラメーターに対する制約は無視されます。For the purposes of these rules, any type parameters associated with S or T are considered to be unique types that have no inheritance relationship with other types, and any constraints on those type parameters are ignored.

この例では、In the example

class C<T> {...}

class D<T>: C<T>
{
    public static implicit operator C<int>(D<T> value) {...}      // Ok
    public static implicit operator C<string>(D<T> value) {...}   // Ok
    public static implicit operator C<T>(D<T> value) {...}        // Error
}

最初の2つの演算子宣言が許可されるのは、インデクサー.3、T および intstring がそれぞれ、リレーションシップのない一意の型と見なされるためです。the first two operator declarations are permitted because, for the purposes of Indexers.3, T and int and string respectively are considered unique types with no relationship. ただし、3番目の演算子はエラーになります。これは C<T>D<T>の基本クラスであるためです。However, the third operator is an error because C<T> is the base class of D<T>.

2番目のルールでは、変換演算子は、演算子が宣言されているクラスまたは構造体型との間で変換を行う必要があることに従います。From the second rule it follows that a conversion operator must convert either to or from the class or struct type in which the operator is declared. たとえば、クラスまたは構造体の型 C は、C から int への変換と int から Cへの変換を定義できますが、int から boolへの変換は定義できません。For example, it is possible for a class or struct type C to define a conversion from C to int and from int to C, but not from int to bool.

定義済みの変換を直接再定義することはできません。It is not possible to directly redefine a pre-defined conversion. したがって、object と他のすべての型の間に暗黙的な変換と明示的な変換が既に存在しているため、変換演算子をまたは object に変換することはできません。Thus, conversion operators are not allowed to convert from or to object because implicit and explicit conversions already exist between object and all other types. 同様に、変換元と変換先の両方の型を他の型の基本型にすることはできません。これは、変換が既に存在するためです。Likewise, neither the source nor the target types of a conversion can be a base type of the other, since a conversion would then already exist.

ただし、特定の型引数に対して、事前定義された変換として既に存在する変換を指定する場合は、ジェネリック型に対して演算子を宣言することができます。However, it is possible to declare operators on generic types that, for particular type arguments, specify conversions that already exist as pre-defined conversions. この例では、In the example

struct Convertible<T>
{
    public static implicit operator Convertible<T>(T value) {...}
    public static explicit operator T(Convertible<T> value) {...}
}

objectTの型引数として指定されている場合、2番目の演算子は、既に存在する変換 (暗黙的な変換でもあり、明示的には、任意の型から object型への変換) を宣言します。when type object is specified as a type argument for T, the second operator declares a conversion that already exists (an implicit, and therefore also an explicit, conversion exists from any type to type object).

2つの型の間に事前定義された変換が存在する場合、これらの型間のユーザー定義の変換はすべて無視されます。In cases where a pre-defined conversion exists between two types, any user-defined conversions between those types are ignored. 具体的な内容は次のとおりです。Specifically:

  • 定義済みの暗黙的な変換 (暗黙の変換) が型 S から T型に存在する場合、S から T へのすべてのユーザー定義変換 (暗黙的または明示的) は無視されます。If a pre-defined implicit conversion (Implicit conversions) exists from type S to type T, all user-defined conversions (implicit or explicit) from S to T are ignored.
  • 定義済みの明示的な変換 (明示的な変換) が型 S から型 Tに存在する場合、S から T へのユーザー定義の明示的な変換はすべて無視されます。If a pre-defined explicit conversion (Explicit conversions) exists from type S to type T, any user-defined explicit conversions from S to T are ignored. さらに、Furthermore:

T がインターフェイス型の場合、S から T へのユーザー定義の暗黙的な変換は無視されます。If T is an interface type, user-defined implicit conversions from S to T are ignored.

それ以外の場合、S から T へのユーザー定義の暗黙的な変換は引き続き考慮されます。Otherwise, user-defined implicit conversions from S to T are still considered.

すべての型に objectますが、上の Convertible<T> 型で宣言された演算子は、事前に定義された変換と競合しません。For all types but object, the operators declared by the Convertible<T> type above do not conflict with pre-defined conversions. 例 :For example:

void F(int i, Convertible<int> n) {
    i = n;                          // Error
    i = (int)n;                     // User-defined explicit conversion
    n = i;                          // User-defined implicit conversion
    n = (Convertible<int>)i;        // User-defined implicit conversion
}

ただし、型 objectの場合、事前定義された変換によって、すべてのケースで1つのユーザー定義変換が非表示になります。However, for type object, pre-defined conversions hide the user-defined conversions in all cases but one:

void F(object o, Convertible<object> n) {
    o = n;                         // Pre-defined boxing conversion
    o = (object)n;                 // Pre-defined boxing conversion
    n = o;                         // User-defined implicit conversion
    n = (Convertible<object>)o;    // Pre-defined unboxing conversion
}

ユーザー定義の変換では、からinterface_typeへの変換は許可されていません。User-defined conversions are not allowed to convert from or to interface_types. 特に、この制限により、 interface_typeへの変換時にユーザー定義の変換が発生しないようにし、変換されるオブジェクトが実際に指定のinterface_typeを実装する場合にのみ、 interface_typeへの変換が成功するようにします。In particular, this restriction ensures that no user-defined transformations occur when converting to an interface_type, and that a conversion to an interface_type succeeds only if the object being converted actually implements the specified interface_type.

変換演算子のシグネチャは、変換元の型と変換先の型で構成されます。The signature of a conversion operator consists of the source type and the target type. (これは、戻り値の型がシグネチャに参加する唯一の形式のメンバーであることに注意してください)。変換演算子の implicit または explicit 分類は、演算子のシグネチャの一部ではありません。(Note that this is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator's signature. したがって、クラスまたは構造体は、implicit と、同じソースとターゲットの型を持つ explicit 変換演算子の両方を宣言することはできません。Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types.

一般に、ユーザー定義の暗黙の変換は、例外をスローせず、情報を失わないように設計する必要があります。In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. ユーザー定義の変換によって例外が発生する可能性がある場合 (たとえば、ソース引数が範囲外の場合) や情報が失われた場合 (上位ビットを破棄する場合など) は、その変換を明示的な変換として定義する必要があります。If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion.

この例では、In the example

using System;

public struct Digit
{
    byte value;

    public Digit(byte value) {
        if (value < 0 || value > 9) throw new ArgumentException();
        this.value = value;
    }

    public static implicit operator byte(Digit d) {
        return d.value;
    }

    public static explicit operator Digit(byte b) {
        return new Digit(b);
    }
}

Digit から byte への変換は、例外をスローしたり情報を失ったりすることはないため、暗黙的に行われますが、Digitbyteの使用可能な値のサブセットのみを表すことができるため、byte から Digit への変換は明示的です。the conversion from Digit to byte is implicit because it never throws exceptions or loses information, but the conversion from byte to Digit is explicit since Digit can only represent a subset of the possible values of a byte.

インスタンスコンストラクターInstance constructors

"インスタンス コンストラクター" は、クラスのインスタンスを初期化するために必要なアクションを実装するメンバーです。An instance constructor is a member that implements the actions required to initialize an instance of a class. インスタンスコンストラクターはconstructor_declarations を使用して宣言されています。Instance constructors are declared using constructor_declarations:

constructor_declaration
    : attributes? constructor_modifier* constructor_declarator constructor_body
    ;

constructor_modifier
    : 'public'
    | 'protected'
    | 'internal'
    | 'private'
    | 'extern'
    | constructor_modifier_unsafe
    ;

constructor_declarator
    : identifier '(' formal_parameter_list? ')' constructor_initializer?
    ;

constructor_initializer
    : ':' 'base' '(' argument_list? ')'
    | ':' 'this' '(' argument_list? ')'
    ;

constructor_body
    : block
    | ';'
    ;

Constructor_declarationには、属性のセット (属性)、4つのアクセス修飾子 (アクセス修飾子) の有効な組み合わせ、および extern (外部メソッド) 修飾子を含めることができます。A constructor_declaration may include a set of attributes (Attributes), a valid combination of the four access modifiers (Access modifiers), and an extern (External methods) modifier. コンストラクター宣言では、同じ修飾子を複数回含めることはできません。A constructor declaration is not permitted to include the same modifier multiple times.

Constructor_declarator識別子は、インスタンスコンストラクターが宣言されているクラスの名前を指定する必要があります。The identifier of a constructor_declarator must name the class in which the instance constructor is declared. 他の名前が指定されている場合は、コンパイル時エラーが発生します。If any other name is specified, a compile-time error occurs.

インスタンスコンストラクターのオプションのformal_parameter_listには、メソッド (メソッド) のformal_parameter_listと同じ規則が適用されます。The optional formal_parameter_list of an instance constructor is subject to the same rules as the formal_parameter_list of a method (Methods). 仮パラメーターリストでは、インスタンスコンストラクターの署名 (シグネチャとオーバーロード) を定義し、オーバーロードの解決 (型の推定) が呼び出しで特定のインスタンスコンストラクターを選択するプロセスを制御します。The formal parameter list defines the signature (Signatures and overloading) of an instance constructor and governs the process whereby overload resolution (Type inference) selects a particular instance constructor in an invocation.

インスタンスコンストラクターのformal_parameter_listで参照される各型は、少なくともコンストラクター自体と同じようにアクセス可能である必要があります (アクセシビリティの制約)。Each of the types referenced in the formal_parameter_list of an instance constructor must be at least as accessible as the constructor itself (Accessibility constraints).

省略可能なconstructor_initializerは、このインスタンスコンストラクターのconstructor_bodyで指定されたステートメントを実行する前に呼び出す別のインスタンスコンストラクターを指定します。The optional constructor_initializer specifies another instance constructor to invoke before executing the statements given in the constructor_body of this instance constructor. これについては、「コンストラクター初期化子」で詳しく説明します。This is described further in Constructor initializers.

コンストラクターの宣言に extern 修飾子が含まれている場合、コンストラクターは外部コンストラクターと呼ばれます。When a constructor declaration includes an extern modifier, the constructor is said to be an external constructor. 外部コンストラクターの宣言は実際の実装を提供しないため、 constructor_bodyはセミコロンで構成されます。Because an external constructor declaration provides no actual implementation, its constructor_body consists of a semicolon. 他のすべてのコンストラクターについては、 constructor_bodyは、クラスの新しいインスタンスを初期化するステートメントを指定するブロックで構成されます。For all other constructors, the constructor_body consists of a block which specifies the statements to initialize a new instance of the class. これは、void 戻り値の型 (メソッド本体) を持つインスタンスメソッドのブロックに正確に対応します。This corresponds exactly to the block of an instance method with a void return type (Method body).

インスタンスコンストラクターは継承されません。Instance constructors are not inherited. したがって、クラスには、クラスで実際に宣言されているコンストラクター以外のインスタンスコンストラクターがありません。Thus, a class has no instance constructors other than those actually declared in the class. クラスにインスタンスコンストラクターの宣言が含まれていない場合は、既定のインスタンスコンストラクターが自動的に提供されます (既定のコンストラクター)。If a class contains no instance constructor declarations, a default instance constructor is automatically provided (Default constructors).

インスタンスコンストラクターはobject_creation_expressions (オブジェクト作成式) およびconstructor_initializerによって呼び出されます。Instance constructors are invoked by object_creation_expressions (Object creation expressions) and through constructor_initializers.

Constructor Initializers (コンストラクター初期化子)Constructor initializers

すべてのインスタンスコンストラクター (クラス objectの場合を除く) には、 constructor_bodyの直前に別のインスタンスコンストラクターを呼び出すことが暗黙的に含まれます。All instance constructors (except those for class object) implicitly include an invocation of another instance constructor immediately before the constructor_body. 暗黙的に呼び出すコンストラクターは、 constructor_initializerによって決定されます。The constructor to implicitly invoke is determined by the constructor_initializer:

  • base(argument_list) または base() フォームのインスタンスコンストラクター初期化子によって、直接の基底クラスのインスタンスコンストラクターが呼び出されます。An instance constructor initializer of the form base(argument_list) or base() causes an instance constructor from the direct base class to be invoked. このコンストラクターは、 argument_list存在する場合は、オーバーロード解決のオーバーロード解決規則を使用して選択されます。That constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. 候補インスタンスコンストラクターのセットは、直接基底クラスに含まれるすべてのアクセス可能なインスタンスコンストラクター、または、直接基底クラスでインスタンスコンストラクターが宣言されていない場合は既定のコンストラクター (既定のコンストラクター) で構成されます。The set of candidate instance constructors consists of all accessible instance constructors contained in the direct base class, or the default constructor (Default constructors), if no instance constructors are declared in the direct base class. このセットが空の場合、または1つの最適なインスタンスコンストラクターを識別できない場合は、コンパイル時エラーが発生します。If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs.
  • this(argument-list) または this() フォームのインスタンスコンストラクター初期化子によって、クラス自体のインスタンスコンストラクターが呼び出されます。An instance constructor initializer of the form this(argument-list) or this() causes an instance constructor from the class itself to be invoked. コンストラクターは、 argument_list存在する場合は、オーバーロード解決のオーバーロード解決規則を使用して選択されます。The constructor is selected using argument_list if present and the overload resolution rules of Overload resolution. 候補インスタンスコンストラクターのセットは、クラス自体で宣言されたすべてのアクセス可能なインスタンスコンストラクターで構成されます。The set of candidate instance constructors consists of all accessible instance constructors declared in the class itself. このセットが空の場合、または1つの最適なインスタンスコンストラクターを識別できない場合は、コンパイル時エラーが発生します。If this set is empty, or if a single best instance constructor cannot be identified, a compile-time error occurs. インスタンスコンストラクターの宣言にコンストラクター自体を呼び出すコンストラクター初期化子が含まれている場合、コンパイル時エラーが発生します。If an instance constructor declaration includes a constructor initializer that invokes the constructor itself, a compile-time error occurs.

インスタンスコンストラクターにコンストラクター初期化子がない場合は、base() フォームのコンストラクター初期化子が暗黙的に指定されます。If an instance constructor has no constructor initializer, a constructor initializer of the form base() is implicitly provided. そのため、フォームのインスタンスコンストラクター宣言Thus, an instance constructor declaration of the form

C(...) {...}

はとまったく同じです。is exactly equivalent to

C(...): base() {...}

インスタンスコンストラクター宣言のformal_parameter_listによって指定されたパラメーターのスコープには、その宣言のコンストラクター初期化子が含まれます。The scope of the parameters given by the formal_parameter_list of an instance constructor declaration includes the constructor initializer of that declaration. したがって、コンストラクターの初期化子は、コンストラクターのパラメーターにアクセスすることが許可されます。Thus, a constructor initializer is permitted to access the parameters of the constructor. 例 :For example:

class A
{
    public A(int x, int y) {}
}

class B: A
{
    public B(int x, int y): base(x + y, x - y) {}
}

インスタンスコンストラクターの初期化子が、作成されているインスタンスにアクセスできません。An instance constructor initializer cannot access the instance being created. したがって、コンストラクター初期化子の引数式で this を参照するにはコンパイル時エラーになります。これは、引数式がsimple_nameを通じてインスタンスメンバーを参照する場合のコンパイル時エラーであるということです。Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple_name.

インスタンス変数初期化子Instance variable initializers

インスタンスコンストラクターにコンストラクター初期化子がない場合、または base(...)フォームのコンストラクター初期化子が存在する場合、そのコンストラクターはクラスで宣言されたインスタンスフィールドのvariable_initializers によって指定された初期化を暗黙的に実行します。When an instance constructor has no constructor initializer, or it has a constructor initializer of the form base(...), that constructor implicitly performs the initializations specified by the variable_initializers of the instance fields declared in its class. これは、コンストラクターへのエントリと、直接基底クラスのコンストラクターの暗黙的な呼び出しの直前に実行される割り当てのシーケンスに対応します。This corresponds to a sequence of assignments that are executed immediately upon entry to the constructor and before the implicit invocation of the direct base class constructor. 変数初期化子は、クラス宣言に含まれるテキスト順に実行されます。The variable initializers are executed in the textual order in which they appear in the class declaration.

コンストラクターの実行Constructor execution

変数初期化子は代入ステートメントに変換され、これらの代入ステートメントは、基底クラスのインスタンスコンストラクターが呼び出される前に実行されます。Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor. この順序により、インスタンスにアクセスできるステートメントが実行される前に、すべてのインスタンスフィールドが変数初期化子によって初期化されます。This ordering ensures that all instance fields are initialized by their variable initializers before any statements that have access to that instance are executed.

例を次に示します。Given the example

using System;

class A
{
    public A() {
        PrintFields();
    }

    public virtual void PrintFields() {}
}

class B: A
{
    int x = 1;
    int y;

    public B() {
        y = -1;
    }

    public override void PrintFields() {
        Console.WriteLine("x = {0}, y = {1}", x, y);
    }
}

Bのインスタンスを作成するために new B() を使用すると、次の出力が生成されます。when new B() is used to create an instance of B, the following output is produced:

x = 1, y = 0

x の値は1です。これは、基底クラスのインスタンスコンストラクターが呼び出される前に変数初期化子が実行されるためです。The value of x is 1 because the variable initializer is executed before the base class instance constructor is invoked. ただし、y の値は 0 (intの既定値) です。 y への割り当ては、基底クラスのコンストラクターが返されるまで実行されないためです。However, the value of y is 0 (the default value of an int) because the assignment to y is not executed until after the base class constructor returns.

インスタンス変数初期化子とコンストラクター初期化子は、 constructor_bodyの前に自動的に挿入されるステートメントと考えると便利です。It is useful to think of instance variable initializers and constructor initializers as statements that are automatically inserted before the constructor_body. The example

using System;
using System.Collections;

class A
{
    int x = 1, y = -1, count;

    public A() {
        count = 0;
    }

    public A(int n) {
        count = n;
    }
}

class B: A
{
    double sqrt2 = Math.Sqrt(2.0);
    ArrayList items = new ArrayList(100);
    int max;

    public B(): this(100) {
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        max = n;
    }
}

複数の変数初期化子が含まれています。また、両方の形式 (basethis) のコンストラクター初期化子も含まれています。contains several variable initializers; it also contains constructor initializers of both forms (base and this). この例は、以下に示すコードに対応しています。各コメントは、自動的に挿入されたステートメントを示します (自動的に挿入されたコンストラクターの呼び出しに使用される構文は有効ではありませんが、単に機構を示すためにのみ機能します)。The example corresponds to the code shown below, where each comment indicates an automatically inserted statement (the syntax used for the automatically inserted constructor invocations isn't valid, but merely serves to illustrate the mechanism).

using System.Collections;

class A
{
    int x, y, count;

    public A() {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = 0;
    }

    public A(int n) {
        x = 1;                       // Variable initializer
        y = -1;                      // Variable initializer
        object();                    // Invoke object() constructor
        count = n;
    }
}

class B: A
{
    double sqrt2;
    ArrayList items;
    int max;

    public B(): this(100) {
        B(100);                      // Invoke B(int) constructor
        items.Add("default");
    }

    public B(int n): base(n - 1) {
        sqrt2 = Math.Sqrt(2.0);      // Variable initializer
        items = new ArrayList(100);  // Variable initializer
        A(n - 1);                    // Invoke A(int) constructor
        max = n;
    }
}

既定のコンストラクターDefault constructors

クラスにインスタンスコンストラクターの宣言が含まれていない場合は、既定のインスタンスコンストラクターが自動的に指定されます。If a class contains no instance constructor declarations, a default instance constructor is automatically provided. この既定のコンストラクターは、単に直接基底クラスのパラメーターなしのコンストラクターを呼び出します。That default constructor simply invokes the parameterless constructor of the direct base class. クラスが abstract の場合、既定のコンストラクターに対して宣言されたアクセシビリティは保護されます。If the class is abstract then the declared accessibility for the default constructor is protected. それ以外の場合、既定のコンストラクターに対して宣言されたアクセシビリティは public になります。Otherwise, the declared accessibility for the default constructor is public. したがって、既定のコンストラクターは常にフォームになります。Thus, the default constructor is always of the form

protected C(): base() {}

、またはor

public C(): base() {}

ここで C はクラスの名前です。where C is the name of the class. オーバーロードの解決で基底クラスのコンストラクターの初期化子に最適な一意の候補を特定できない場合、コンパイル時エラーが発生します。If overload resolution is unable to determine a unique best candidate for the base class constructor initializer then a compile-time error occurs.

この例では、In the example

class Message
{
    object sender;
    string text;
}

クラスにはインスタンスコンストラクターの宣言が含まれていないため、既定のコンストラクターが用意されています。a default constructor is provided because the class contains no instance constructor declarations. したがって、この例はとまったく同じです。Thus, the example is precisely equivalent to

class Message
{
    object sender;
    string text;

    public Message(): base() {}
}

プライベートコンストラクターPrivate constructors

クラス T がプライベートインスタンスコンストラクターのみを宣言する場合、T のプログラムテキストの外部のクラスは T から派生したり、Tのインスタンスを直接作成したりすることはできません。When a class T declares only private instance constructors, it is not possible for classes outside the program text of T to derive from T or to directly create instances of T. したがって、クラスに静的メンバーのみが含まれ、インスタンス化されない場合は、空のプライベートインスタンスコンストラクターを追加すると、インスタンス化ができなくなります。Thus, if a class contains only static members and isn't intended to be instantiated, adding an empty private instance constructor will prevent instantiation. 例 :For example:

public class Trig
{
    private Trig() {}        // Prevent instantiation

    public const double PI = 3.14159265358979323846;

    public static double Sin(double x) {...}
    public static double Cos(double x) {...}
    public static double Tan(double x) {...}
}

Trig クラスは、関連するメソッドと定数をグループ化しますが、インスタンス化するためのものではありません。The Trig class groups related methods and constants, but is not intended to be instantiated. したがって、1つの空のプライベートインスタンスコンストラクターを宣言します。Therefore it declares a single empty private instance constructor. 既定のコンストラクターが自動生成されないようにするには、少なくとも1つのインスタンスコンストラクターを宣言する必要があります。At least one instance constructor must be declared to suppress the automatic generation of a default constructor.

省略可能なインスタンスコンストラクターパラメーターOptional instance constructor parameters

コンストラクター初期化子の this(...) 形式は、一般に、省略可能なインスタンスコンストラクターパラメーターを実装するためにオーバーロードと組み合わせて使用されます。The this(...) form of constructor initializer is commonly used in conjunction with overloading to implement optional instance constructor parameters. この例では、In the example

class Text
{
    public Text(): this(0, 0, null) {}

    public Text(int x, int y): this(x, y, null) {}

    public Text(int x, int y, string s) {
        // Actual constructor implementation
    }
}

最初の2つのインスタンスコンストラクターは、不足している引数の既定値を提供するだけです。the first two instance constructors merely provide the default values for the missing arguments. どちらも、this(...) コンストラクター初期化子を使用して3番目のインスタンスコンストラクターを呼び出します。これにより、実際には、新しいインスタンスを初期化する作業が行われます。Both use a this(...) constructor initializer to invoke the third instance constructor, which actually does the work of initializing the new instance. これは、省略可能なコンストラクターパラメーターの効果です。The effect is that of optional constructor parameters:

Text t1 = new Text();                    // Same as Text(0, 0, null)
Text t2 = new Text(5, 10);               // Same as Text(5, 10, null)
Text t3 = new Text(5, 20, "Hello");

静的コンストラクターStatic constructors

静的コンストラクターは、closed クラス型を初期化するために必要なアクションを実装するメンバーです。A static constructor is a member that implements the actions required to initialize a closed class type. 静的コンストラクターはstatic_constructor_declarations を使用して宣言されます。Static constructors are declared using static_constructor_declarations:

static_constructor_declaration
    : attributes? static_constructor_modifiers identifier '(' ')' static_constructor_body
    ;

static_constructor_modifiers
    : 'extern'? 'static'
    | 'static' 'extern'?
    | static_constructor_modifiers_unsafe
    ;

static_constructor_body
    : block
    | ';'
    ;

Static_constructor_declarationには、一連の属性(属性) と extern 修飾子 (外部メソッド) を含めることができます。A static_constructor_declaration may include a set of attributes (Attributes) and an extern modifier (External methods).

Static_constructor_declaration識別子は、静的コンストラクターが宣言されているクラスの名前を指定する必要があります。The identifier of a static_constructor_declaration must name the class in which the static constructor is declared. 他の名前が指定されている場合は、コンパイル時エラーが発生します。If any other name is specified, a compile-time error occurs.

静的コンストラクターの宣言に extern 修飾子が含まれている場合、静的コンストラクターは外部の静的コンストラクターと呼ばれます。When a static constructor declaration includes an extern modifier, the static constructor is said to be an external static constructor. 外部の静的コンストラクター宣言は実際の実装を提供しないため、 static_constructor_bodyはセミコロンで構成されます。Because an external static constructor declaration provides no actual implementation, its static_constructor_body consists of a semicolon. その他のすべての静的コンストラクター宣言では、 static_constructor_bodyは、クラスを初期化するために実行するステートメントを指定するブロックで構成されます。For all other static constructor declarations, the static_constructor_body consists of a block which specifies the statements to execute in order to initialize the class. これは、void 戻り値の型 (メソッド本体) を持つ静的メソッドのmethod_bodyに相当します。This corresponds exactly to the method_body of a static method with a void return type (Method body).

静的コンストラクターは継承されず、直接呼び出すことはできません。Static constructors are not inherited, and cannot be called directly.

Closed クラス型の静的コンストラクターは、特定のアプリケーションドメインで1回だけ実行されます。The static constructor for a closed class type executes at most once in a given application domain. 静的コンストラクターの実行は、アプリケーションドメイン内で発生する次のイベントの最初のイベントによってトリガーされます。The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • クラス型のインスタンスが作成されます。An instance of the class type is created.
  • クラス型のいずれかの静的メンバーが参照されています。Any of the static members of the class type are referenced.

実行を開始する Main メソッド (アプリケーションのスタートアップ) がクラスに含まれている場合、そのクラスの静的コンストラクターは、Main メソッドが呼び出される前に実行されます。If a class contains the Main method (Application Startup) in which execution begins, the static constructor for that class executes before the Main method is called.

クローズしたクラスの新しい型を初期化するには、まず、その特定のクローズされた型の新しい静的フィールド (静的フィールドとインスタンスフィールド) のセットを作成します。To initialize a new closed class type, first a new set of static fields (Static and instance fields) for that particular closed type is created. 各静的フィールドは、既定値 (既定値) に初期化されます。Each of the static fields is initialized to its default value (Default values). 次に、静的フィールドの初期化子 (静的フィールドの初期化) を静的フィールドに対して実行します。Next, the static field initializers (Static field initialization) are executed for those static fields. 最後に、静的コンストラクターが実行されます。Finally, the static constructor is executed.

The example

using System;

class Test
{
    static void Main() {
        A.F();
        B.F();
    }
}

class A
{
    static A() {
        Console.WriteLine("Init A");
    }
    public static void F() {
        Console.WriteLine("A.F");
    }
}

class B
{
    static B() {
        Console.WriteLine("Init B");
    }
    public static void F() {
        Console.WriteLine("B.F");
    }
}

出力を生成する必要があります。must produce the output:

Init A
A.F
Init B
B.F

Aの静的コンストラクターの実行は A.Fへの呼び出しによってトリガーされるため、Bの静的コンストラクターの実行は B.Fへの呼び出しによってトリガーされます。because the execution of A's static constructor is triggered by the call to A.F, and the execution of B's static constructor is triggered by the call to B.F.

変数初期化子を持つ静的フィールドを既定値の状態で観察できるようにする、循環依存関係を構築することができます。It is possible to construct circular dependencies that allow static fields with variable initializers to be observed in their default value state.

The example

using System;

class A
{
    public static int X;

    static A() {
        X = B.Y + 1;
    }
}

class B
{
    public static int Y = A.X + 1;

    static B() {}

    static void Main() {
        Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y);
    }
}

この例では、次のように出力されます。produces the output

X = 1, Y = 2

Main メソッドを実行するために、システムはまず、クラス Bの静的コンストラクターの前に B.Yの初期化子を実行します。To execute the Main method, the system first runs the initializer for B.Y, prior to class B's static constructor. A.X の値が参照されているため、Yの初期化子によって Aの静的コンストラクターが実行されます。Y's initializer causes A's static constructor to be run because the value of A.X is referenced.  A の静的コンストラクターは、 Xの値の計算を続行します。これにより、 Yの既定値 (0) がフェッチされます。The static constructor of A in turn proceeds to compute the value of X, and in doing so fetches the default value of Y, which is zero. したがって A.X が1に初期化されます。A.X is thus initialized to 1. Aの静的フィールド初期化子と静的コンストラクターを実行するプロセスが完了し、 Yの初期値の計算に戻ります。結果は2になります。The process of running A's static field initializers and static constructor then completes, returning to the calculation of the initial value of Y, the result of which becomes 2.

静的コンストラクターは、終了した構築済みのクラス型ごとに1回だけ実行されるため、制約 (型パラメーターの制約) によってコンパイル時にチェックできない型パラメーターに対してランタイムチェックを適用するのに便利な場所です。Because the static constructor is executed exactly once for each closed constructed class type, it is a convenient place to enforce run-time checks on the type parameter that cannot be checked at compile-time via constraints (Type parameter constraints). たとえば、次の型では、静的コンストラクターを使用して、型引数が列挙型であることを強制しています。For example, the following type uses a static constructor to enforce that the type argument is an enum:

class Gen<T> where T: struct
{
    static Gen() {
        if (!typeof(T).IsEnum) {
            throw new ArgumentException("T must be an enum");
        }
    }
}

デストラクターDestructors

デストラクターは、クラスのインスタンスを消滅させるために必要なアクションを実装するメンバーです。A destructor is a member that implements the actions required to destruct an instance of a class. デストラクターはdestructor_declarationを使用して宣言されます。A destructor is declared using a destructor_declaration:

destructor_declaration
    : attributes? 'extern'? '~' identifier '(' ')' destructor_body
    | destructor_declaration_unsafe
    ;

destructor_body
    : block
    | ';'
    ;

Destructor_declarationには、一連の属性(属性) を含めることができます。A destructor_declaration may include a set of attributes (Attributes).

Destructor_declaration識別子は、デストラクターが宣言されているクラスの名前を指定する必要があります。The identifier of a destructor_declaration must name the class in which the destructor is declared. 他の名前が指定されている場合は、コンパイル時エラーが発生します。If any other name is specified, a compile-time error occurs.

デストラクター宣言に extern 修飾子が含まれている場合、デストラクターは外部デストラクターと呼ばれます。When a destructor declaration includes an extern modifier, the destructor is said to be an external destructor. 外部デストラクター宣言は実際の実装を提供しないため、 destructor_bodyはセミコロンで構成されます。Because an external destructor declaration provides no actual implementation, its destructor_body consists of a semicolon. その他のすべてのデストラクターでは、 destructor_bodyは、クラスのインスタンスを破棄するために実行するステートメントを指定するブロックで構成されます。For all other destructors, the destructor_body consists of a block which specifies the statements to execute in order to destruct an instance of the class. Destructor_bodyは、void の戻り値の型 (メソッド本体) を持つインスタンスメソッドのmethod_bodyに正確に対応します。A destructor_body corresponds exactly to the method_body of an instance method with a void return type (Method body).

デストラクターは継承されません。Destructors are not inherited. したがって、クラスには、そのクラスで宣言されている可能性のあるデストラクターがありません。Thus, a class has no destructors other than the one which may be declared in that class.

デストラクターにはパラメーターが必要ないため、オーバーロードすることはできないため、クラスは最大で1つのデストラクターを持つことができます。Since a destructor is required to have no parameters, it cannot be overloaded, so a class can have, at most, one destructor.

デストラクターは自動的に呼び出されるため、明示的に呼び出すことはできません。Destructors are invoked automatically, and cannot be invoked explicitly. インスタンスをコードで使用することができなくなった場合、インスタンスは破棄の対象になります。An instance becomes eligible for destruction when it is no longer possible for any code to use that instance. インスタンスのデストラクターの実行は、インスタンスが破棄の対象になった後、いつでも発生する可能性があります。Execution of the destructor for the instance may occur at any time after the instance becomes eligible for destruction. インスタンスが破棄されされると、そのインスタンスの継承チェーン内のデストラクターは、ほとんどの派生から最小の派生まで、順に呼び出されます。When an instance is destructed, the destructors in that instance's inheritance chain are called, in order, from most derived to least derived. デストラクターは、任意のスレッドで実行できます。A destructor may be executed on any thread. デストラクターを実行するタイミングと方法を制御する規則の詳細については、「自動メモリ管理」を参照してください。For further discussion of the rules that govern when and how a destructor is executed, see Automatic memory management.

例の出力The output of the example

using System;

class A
{
    ~A() {
        Console.WriteLine("A's destructor");
    }
}

class B: A
{
    ~B() {
        Console.WriteLine("B's destructor");
    }
}

class Test
{
   static void Main() {
        B b = new B();
        b = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
   }
}

isis

B's destructor
A's destructor

継承チェーン内のデストラクターは、ほとんどの派生から最小の派生から順に呼び出されるためです。since destructors in an inheritance chain are called in order, from most derived to least derived.

デストラクターは、System.ObjectFinalize 仮想メソッドをオーバーライドすることによって実装されます。Destructors are implemented by overriding the virtual method Finalize on System.Object. C#プログラムでは、このメソッドのオーバーライドまたは呼び出し (またはそのオーバーライド) を直接行うことはできません。C# programs are not permitted to override this method or call it (or overrides of it) directly. たとえば、プログラムFor instance, the program

class A 
{
    override protected void Finalize() {}    // error

    public void F() {
        this.Finalize();                     // error
    }
}

2つのエラーが含まれています。contains two errors.

コンパイラは、このメソッドとオーバーライドがまったく存在しないかのように動作します。The compiler behaves as if this method, and overrides of it, do not exist at all. そのため、このプログラムは次のようになります。Thus, this program:

class A 
{
    void Finalize() {}                            // permitted
}

が有効であり、表示されているメソッドが System.ObjectFinalize メソッドを非表示にします。is valid, and the method shown hides System.Object's Finalize method.

デストラクターから例外がスローされた場合の動作の詳細については、「例外の処理方法」を参照してください。For a discussion of the behavior when an exception is thrown from a destructor, see How exceptions are handled.

反復子Iterators

反復子ブロック (ブロック) を使用して実装される関数メンバー (関数メンバー) は、反復子と呼ばれます。A function member (Function members) implemented using an iterator block (Blocks) is called an iterator.

対応する関数メンバーの戻り値の型が列挙子インターフェイス (列挙子インターフェイス) の1つであるか、または列挙可能なインターフェイス (列挙可能なインターフェイス) の1つである限り、反復子ブロックは関数メンバーの本体として使用できます。An iterator block may be used as the body of a function member as long as the return type of the corresponding function member is one of the enumerator interfaces (Enumerator interfaces) or one of the enumerable interfaces (Enumerable interfaces). これは、 method_bodyoperator_bodyまたはaccessor_bodyとして発生する可能性があります。一方、イベント、インスタンスコンストラクター、静的コンストラクター、およびデストラクターを反復子として実装することはできません。It can occur as a method_body, operator_body or accessor_body, whereas events, instance constructors, static constructors and destructors cannot be implemented as iterators.

関数メンバーが反復子ブロックを使用して実装されている場合、関数メンバーの仮パラメーターリストで ref または out パラメーターを指定すると、コンパイル時エラーになります。When a function member is implemented using an iterator block, it is a compile-time error for the formal parameter list of the function member to specify any ref or out parameters.

列挙子インターフェイスEnumerator interfaces

列挙子インターフェイスは、非ジェネリックインターフェイス System.Collections.IEnumerator と、ジェネリックインターフェイス System.Collections.Generic.IEnumerator<T>のすべてのインスタンス化です。The enumerator interfaces are the non-generic interface System.Collections.IEnumerator and all instantiations of the generic interface System.Collections.Generic.IEnumerator<T>. 簡潔にするために、この章では、これらのインターフェイスをそれぞれ IEnumeratorIEnumerator<T>として参照しています。For the sake of brevity, in this chapter these interfaces are referenced as IEnumerator and IEnumerator<T>, respectively.

列挙可能なインターフェイスEnumerable interfaces

列挙可能なインターフェイスは、非ジェネリックインターフェイス System.Collections.IEnumerable と、ジェネリックインターフェイス System.Collections.Generic.IEnumerable<T>のすべてのインスタンス化です。The enumerable interfaces are the non-generic interface System.Collections.IEnumerable and all instantiations of the generic interface System.Collections.Generic.IEnumerable<T>. 簡潔にするために、この章では、これらのインターフェイスをそれぞれ IEnumerableIEnumerable<T>として参照しています。For the sake of brevity, in this chapter these interfaces are referenced as IEnumerable and IEnumerable<T>, respectively.

Yield 型Yield type

反復子は、すべて同じ型の値のシーケンスを生成します。An iterator produces a sequence of values, all of the same type. この型は、反復子のyield 型と呼ばれます。This type is called the yield type of the iterator.

  • IEnumerator を返す反復子の yield 型、または IEnumerableobjectである。The yield type of an iterator that returns IEnumerator or IEnumerable is object.
  • IEnumerator<T> を返す反復子の yield 型、または IEnumerable<T>Tである。The yield type of an iterator that returns IEnumerator<T> or IEnumerable<T> is T.

列挙子オブジェクトEnumerator objects

列挙子インターフェイス型を返す関数メンバーが反復子ブロックを使用して実装されている場合、関数メンバーを呼び出すと反復子ブロックのコードはすぐには実行されません。When a function member returning an enumerator interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. 代わりに、列挙子オブジェクトが作成され、返されます。Instead, an enumerator object is created and returned. このオブジェクトは、反復子ブロックで指定されたコードをカプセル化し、列挙子オブジェクトの MoveNext メソッドが呼び出されたときに反復子ブロック内のコードを実行します。This object encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. 列挙子オブジェクトには、次の特性があります。An enumerator object has the following characteristics:

  • IEnumeratorIEnumerator<T>を実装します。 T は反復子の yield 型です。It implements IEnumerator and IEnumerator<T>, where T is the yield type of the iterator.
  • このクラスは、System.IDisposable を実装します。It implements System.IDisposable.
  • 引数値 (存在する場合) と、関数メンバーに渡されるインスタンス値のコピーを使用して初期化されます。It is initialized with a copy of the argument values (if any) and instance value passed to the function member.
  • これには、""、"実行中"、"中断"、および "" の4つの状態があり、最初は "" の状態になります。It has four potential states, before, running, suspended, and after, and is initially in the before state.

列挙子オブジェクトは、通常、コンパイラによって生成される列挙子クラスのインスタンスであり、反復子ブロックのコードをカプセル化し、列挙子インターフェイスを実装しますが、その他の実装方法も可能です。An enumerator object is typically an instance of a compiler-generated enumerator class that encapsulates the code in the iterator block and implements the enumerator interfaces, but other methods of implementation are possible. 列挙子クラスがコンパイラによって生成される場合、そのクラスは、関数メンバーを含むクラスで直接的または間接的に入れ子にされ、プライベートアクセシビリティを持ち、コンパイラで使用するために予約された名前 (識別子) になります。If an enumerator class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

列挙子オブジェクトには、上で指定したものよりも多くのインターフェイスを実装できます。An enumerator object may implement more interfaces than those specified above.

次のセクションでは、列挙子オブジェクトによって提供される IEnumerable および IEnumerable<T> インターフェイスの実装の MoveNextCurrent、および Dispose メンバーの正確な動作について説明します。The following sections describe the exact behavior of the MoveNext, Current, and Dispose members of the IEnumerable and IEnumerable<T> interface implementations provided by an enumerator object.

列挙子オブジェクトは、IEnumerator.Reset メソッドをサポートしていないことに注意してください。Note that enumerator objects do not support the IEnumerator.Reset method. このメソッドを呼び出すと System.NotSupportedException がスローされます。Invoking this method causes a System.NotSupportedException to be thrown.

MoveNext メソッドThe MoveNext method

列挙子オブジェクトの MoveNext メソッドは、反復子ブロックのコードをカプセル化します。The MoveNext method of an enumerator object encapsulates the code of an iterator block. MoveNext メソッドを呼び出すと、反復子ブロック内のコードが実行され、必要に応じて列挙子オブジェクトの Current プロパティが設定されます。Invoking the MoveNext method executes code in the iterator block and sets the Current property of the enumerator object as appropriate. MoveNext によって実行される正確なアクションは、MoveNext が呼び出されたときの列挙子オブジェクトの状態によって異なります。The precise action performed by MoveNext depends on the state of the enumerator object when MoveNext is invoked:

  • 列挙子オブジェクトの状態が以前である場合は、MoveNextを呼び出します。If the state of the enumerator object is before, invoking MoveNext:
    • 状態を実行中に変更します。Changes the state to running.
    • 反復子オブジェクトが初期化されたときに保存された引数値とインスタンス値に対して、反復子ブロックのパラメーター (thisを含む) を初期化します。Initializes the parameters (including this) of the iterator block to the argument values and instance value saved when the enumerator object was initialized.
    • 次に示すように、実行が中断されるまで、最初から反復子ブロックを実行します。Executes the iterator block from the beginning until execution is interrupted (as described below).
  • 列挙子オブジェクトの状態が [実行中] の場合、MoveNext を呼び出した結果は指定されません。If the state of the enumerator object is running, the result of invoking MoveNext is unspecified.
  • 列挙子オブジェクトの状態が中断されている場合は MoveNextを呼び出します。If the state of the enumerator object is suspended, invoking MoveNext:
    • 状態を実行中に変更します。Changes the state to running.
    • すべてのローカル変数とパラメーター (this を含む) の値を、反復子ブロックの実行が最後に中断されたときに保存された値に復元します。Restores the values of all local variables and parameters (including this) to the values saved when execution of the iterator block was last suspended. これらの変数によって参照されるオブジェクトの内容は、MoveNext の前の呼び出し以降に変更されている可能性があることに注意してください。Note that the contents of any objects referenced by these variables may have changed since the previous call to MoveNext.
    • 実行の中断の原因となった yield return ステートメントのすぐ後に反復子ブロックの実行を再開し、実行が中断されるまで続行します (後述)。Resumes execution of the iterator block immediately following the yield return statement that caused the suspension of execution and continues until execution is interrupted (as described below).
  • 列挙子オブジェクトの状態がのにある場合は、MoveNext を呼び出すと falseが返されます。If the state of the enumerator object is after, invoking MoveNext returns false.

MoveNext が反復子ブロックを実行すると、4つの方法で実行を中断できます。これには、yield return ステートメント、yield break ステートメント、反復子ブロックの終わりを検出し、例外がスローされ、反復子ブロックの外に伝達されます。When MoveNext executes the iterator block, execution can be interrupted in four ways: By a yield return statement, by a yield break statement, by encountering the end of the iterator block, and by an exception being thrown and propagated out of the iterator block.

  • yield return ステートメントが発生したとき (yield ステートメント):When a yield return statement is encountered (The yield statement):
    • ステートメントで指定された式が評価され、暗黙的に yield 型に変換され、列挙子オブジェクトの Current プロパティに割り当てられます。The expression given in the statement is evaluated, implicitly converted to the yield type, and assigned to the Current property of the enumerator object.
    • 反復子本体の実行は中断されています。Execution of the iterator body is suspended. この yield return ステートメントの場所と同様に、すべてのローカル変数とパラメーター (thisを含む) の値が保存されます。The values of all local variables and parameters (including this) are saved, as is the location of this yield return statement. yield return ステートメントが1つ以上の try ブロック内にある場合、関連付けられた finally ブロックは現時点では実行されません。If the yield return statement is within one or more try blocks, the associated finally blocks are not executed at this time.
    • 列挙子オブジェクトの状態が "中断" に変更されます。The state of the enumerator object is changed to suspended.
    • MoveNext メソッドは、true を呼び出し元に返します。これは、反復処理が次の値に正常に進んだことを示します。The MoveNext method returns true to its caller, indicating that the iteration successfully advanced to the next value.
  • yield break ステートメントが発生したとき (yield ステートメント):When a yield break statement is encountered (The yield statement):
    • yield break ステートメントが1つ以上の try ブロック内にある場合は、関連付けられた finally ブロックが実行されます。If the yield break statement is within one or more try blocks, the associated finally blocks are executed.
    • 列挙子オブジェクトの状態がafterに変更されます。The state of the enumerator object is changed to after.
    • MoveNext メソッドは、反復処理が完了したことを示す false を呼び出し元に返します。The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • 反復子本体の終わりが見つかった場合:When the end of the iterator body is encountered:
    • 列挙子オブジェクトの状態がafterに変更されます。The state of the enumerator object is changed to after.
    • MoveNext メソッドは、反復処理が完了したことを示す false を呼び出し元に返します。The MoveNext method returns false to its caller, indicating that the iteration is complete.
  • 例外がスローされ、反復子ブロックの外に伝達される場合:When an exception is thrown and propagated out of the iterator block:
    • 反復子本体内の適切な finally ブロックは、例外の反映によって実行されます。Appropriate finally blocks in the iterator body will have been executed by the exception propagation.
    • 列挙子オブジェクトの状態がafterに変更されます。The state of the enumerator object is changed to after.
    • 例外の伝達は、MoveNext メソッドの呼び出し元に続きます。The exception propagation continues to the caller of the MoveNext method.

現在のプロパティThe Current property

列挙子オブジェクトの Current プロパティは、反復子ブロック内の yield return ステートメントの影響を受けます。An enumerator object's Current property is affected by yield return statements in the iterator block.

列挙子オブジェクトが中断状態にある場合、Current の値は、前に MoveNextを呼び出したときに設定された値になります。When an enumerator object is in the suspended state, the value of Current is the value set by the previous call to MoveNext. 列挙子オブジェクトが []、[実行中]、または [] の状態にある場合、Current にアクセスした結果は指定されません。When an enumerator object is in the before, running, or after states, the result of accessing Current is unspecified.

object以外の yield 型を持つ反復子の場合、列挙子オブジェクトの IEnumerable 実装を通じて Current にアクセスしたときの結果は、列挙子オブジェクトの IEnumerator<T> 実装を通じて Current にアクセスし、結果を objectにキャストすることと対応しています。For an iterator with a yield type other than object, the result of accessing Current through the enumerator object's IEnumerable implementation corresponds to accessing Current through the enumerator object's IEnumerator<T> implementation and casting the result to object.

Dispose メソッドThe Dispose method

Dispose メソッドは、列挙子オブジェクトをafter状態にすることによって、反復処理をクリーンアップするために使用されます。The Dispose method is used to clean up the iteration by bringing the enumerator object to the after state.

  • 列挙子オブジェクトの状態が以前の場合、 Dispose を呼び出すと、状態がに変更されます。If the state of the enumerator object is before, invoking Dispose changes the state to after.
  • 列挙子オブジェクトの状態が [実行中] の場合、Dispose を呼び出した結果は指定されません。If the state of the enumerator object is running, the result of invoking Dispose is unspecified.
  • 列挙子オブジェクトの状態が中断されている場合は Disposeを呼び出します。If the state of the enumerator object is suspended, invoking Dispose:
    • 状態を実行中に変更します。Changes the state to running.
    • 最後に実行された yield return ステートメントが yield break ステートメントであったかのように、finally ブロックを実行します。Executes any finally blocks as if the last executed yield return statement were a yield break statement. これによって例外がスローされ、反復子本体の外に伝達される場合、列挙子オブジェクトの状態がafterに設定され、例外が Dispose メソッドの呼び出し元に反映されます。If this causes an exception to be thrown and propagated out of the iterator body, the state of the enumerator object is set to after and the exception is propagated to the caller of the Dispose method.
    • 状態をのに変更します。Changes the state to after.
  • 列挙子オブジェクトの状態がのにある場合、Dispose を呼び出すことはできません。If the state of the enumerator object is after, invoking Dispose has no affect.

列挙可能なオブジェクトEnumerable objects

列挙可能なインターフェイス型を返す関数メンバーが反復子ブロックを使用して実装されている場合、関数メンバーを呼び出すと、反復子ブロックのコードはすぐには実行されません。When a function member returning an enumerable interface type is implemented using an iterator block, invoking the function member does not immediately execute the code in the iterator block. 代わりに、列挙可能なオブジェクトが作成されて返されます。Instead, an enumerable object is created and returned. 列挙可能なオブジェクトの GetEnumerator メソッドは、反復子ブロックで指定されたコードをカプセル化する列挙子オブジェクトを返します。反復子オブジェクトの MoveNext メソッドが呼び出されると、反復子ブロック内のコードが実行されます。The enumerable object's GetEnumerator method returns an enumerator object that encapsulates the code specified in the iterator block, and execution of the code in the iterator block occurs when the enumerator object's MoveNext method is invoked. 列挙可能なオブジェクトには、次の特性があります。An enumerable object has the following characteristics:

  • IEnumerableIEnumerable<T>を実装します。 T は反復子の yield 型です。It implements IEnumerable and IEnumerable<T>, where T is the yield type of the iterator.
  • 引数値 (存在する場合) と、関数メンバーに渡されるインスタンス値のコピーを使用して初期化されます。It is initialized with a copy of the argument values (if any) and instance value passed to the function member.

列挙可能なオブジェクトは、通常、コンパイラによって生成される列挙可能なクラスのインスタンスであり、反復子ブロックのコードをカプセル化し、列挙可能なインターフェイスを実装しますが、その他の実装方法も可能です。An enumerable object is typically an instance of a compiler-generated enumerable class that encapsulates the code in the iterator block and implements the enumerable interfaces, but other methods of implementation are possible. 列挙可能なクラスがコンパイラによって生成される場合、そのクラスは、関数メンバーを含むクラスで直接的または間接的に入れ子にされ、プライベートアクセシビリティを持ち、コンパイラで使用するために予約された名前 (識別子) になります。If an enumerable class is generated by the compiler, that class will be nested, directly or indirectly, in the class containing the function member, it will have private accessibility, and it will have a name reserved for compiler use (Identifiers).

列挙可能なオブジェクトは、上で指定したものよりも多くのインターフェイスを実装できます。An enumerable object may implement more interfaces than those specified above. 特に、列挙可能なオブジェクトは IEnumeratorIEnumerator<T>を実装して、列挙可能と列挙子の両方として機能できるようにすることもできます。In particular, an enumerable object may also implement IEnumerator and IEnumerator<T>, enabling it to serve as both an enumerable and an enumerator. この種類の実装では、列挙可能なオブジェクトの GetEnumerator メソッドが初めて呼び出されるときに、列挙可能なオブジェクト自体が返されます。In that type of implementation, the first time an enumerable object's GetEnumerator method is invoked, the enumerable object itself is returned. その後、列挙可能なオブジェクトの GetEnumeratorを呼び出すと、列挙可能なオブジェクトのコピーが返されます。Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. したがって、返される各列挙子には独自の状態があり、1つの列挙子の変更は別の列挙子に影響しません。Thus, each returned enumerator has its own state and changes in one enumerator will not affect another.

GetEnumerator メソッドThe GetEnumerator method

列挙可能なオブジェクトは、IEnumerable および IEnumerable<T> インターフェイスの GetEnumerator メソッドの実装を提供します。An enumerable object provides an implementation of the GetEnumerator methods of the IEnumerable and IEnumerable<T> interfaces. 2つの GetEnumerator メソッドは、使用可能な列挙子オブジェクトを取得して返す共通の実装を共有します。The two GetEnumerator methods share a common implementation that acquires and returns an available enumerator object. 列挙子オブジェクトは、列挙可能なオブジェクトが初期化されたときに保存された引数値とインスタンス値を使用して初期化されますが、それ以外の場合は、列挙子オブジェクトは「 enumerator オブジェクト」の説明に従って機能します。The enumerator object is initialized with the argument values and instance value saved when the enumerable object was initialized, but otherwise the enumerator object functions as described in Enumerator objects.

実装の例Implementation example

このセクションでは、標準的C#なコンストラクトに関して、反復子の実装について説明します。This section describes a possible implementation of iterators in terms of standard C# constructs. ここで説明する実装は、Microsoft C#コンパイラで使用されるのと同じ原則に基づいていますが、必須の実装であるか、または可能な唯一の方法ではありません。The implementation described here is based on the same principles used by the Microsoft C# compiler, but it is by no means a mandated implementation or the only one possible.

次の Stack<T> クラスは、反復子を使用して、その GetEnumerator メソッドを実装します。The following Stack<T> class implements its GetEnumerator method using an iterator. 反復子は、スタックの要素を上から下の順に列挙します。The iterator enumerates the elements of the stack in top to bottom order.

using System;
using System.Collections;
using System.Collections.Generic;

class Stack<T>: IEnumerable<T>
{
    T[] items;
    int count;

    public void Push(T item) {
        if (items == null) {
            items = new T[4];
        }
        else if (items.Length == count) {
            T[] newItems = new T[count * 2];
            Array.Copy(items, 0, newItems, 0, count);
            items = newItems;
        }
        items[count++] = item;
    }

    public T Pop() {
        T result = items[--count];
        items[count] = default(T);
        return result;
    }

    public IEnumerator<T> GetEnumerator() {
        for (int i = count - 1; i >= 0; --i) yield return items[i];
    }
}

GetEnumerator メソッドは、次に示すように、反復子ブロックのコードをカプセル化する、コンパイラによって生成される列挙子クラスのインスタンス化に変換できます。The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Stack<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1: IEnumerator<T>, IEnumerator
    {
        int __state;
        T __current;
        Stack<T> __this;
        int i;

        public __Enumerator1(Stack<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
                case 1: goto __state1;
                case 2: goto __state2;
            }
            i = __this.count - 1;
        __loop:
            if (i < 0) goto __state2;
            __current = __this.items[i];
            __state = 1;
            return true;
        __state1:
            --i;
            goto __loop;
        __state2:
            __state = 2;
            return false;
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

前の変換では、反復子ブロック内のコードはステートマシンに変換され、enumerator クラスの MoveNext メソッドに配置されます。In the preceding translation, the code in the iterator block is turned into a state machine and placed in the MoveNext method of the enumerator class. さらに、ローカル変数 i が列挙子オブジェクトのフィールドに変換されるため、MoveNextの呼び出しの間に存在し続けることができます。Furthermore, the local variable i is turned into a field in the enumerator object so it can continue to exist across invocations of MoveNext.

次の例では、1 ~ 10 の整数の単純な乗算テーブルを出力します。The following example prints a simple multiplication table of the integers 1 through 10. この例の FromTo メソッドは、列挙可能なオブジェクトを返し、反復子を使用して実装されます。The FromTo method in the example returns an enumerable object and is implemented using an iterator.

using System;
using System.Collections.Generic;

class Test
{
    static IEnumerable<int> FromTo(int from, int to) {
        while (from <= to) yield return from++;
    }

    static void Main() {
        IEnumerable<int> e = FromTo(1, 10);
        foreach (int x in e) {
            foreach (int y in e) {
                Console.Write("{0,3} ", x * y);
            }
            Console.WriteLine();
        }
    }
}

FromTo メソッドは、次に示すように、反復子ブロックのコードをカプセル化する、コンパイラによって生成される列挙可能なクラスのインスタンス化に変換できます。The FromTo method can be translated into an instantiation of a compiler-generated enumerable class that encapsulates the code in the iterator block, as shown in the following.

using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;

class Test
{
    ...

    static IEnumerable<int> FromTo(int from, int to) {
        return new __Enumerable1(from, to);
    }

    class __Enumerable1:
        IEnumerable<int>, IEnumerable,
        IEnumerator<int>, IEnumerator
    {
        int __state;
        int __current;
        int __from;
        int from;
        int to;
        int i;

        public __Enumerable1(int __from, int to) {
            this.__from = __from;
            this.to = to;
        }

        public IEnumerator<int> GetEnumerator() {
            __Enumerable1 result = this;
            if (Interlocked.CompareExchange(ref __state, 1, 0) != 0) {
                result = new __Enumerable1(__from, to);
                result.__state = 1;
            }
            result.from = result.__from;
            return result;
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return (IEnumerator)GetEnumerator();
        }

        public int Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            switch (__state) {
            case 1:
                if (from > to) goto case 2;
                __current = from++;
                __state = 1;
                return true;
            case 2:
                __state = 2;
                return false;
            default:
                throw new InvalidOperationException();
            }
        }

        public void Dispose() {
            __state = 2;
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

列挙可能なクラスは、列挙可能なインターフェイスと列挙子インターフェイスの両方を実装します。これにより、列挙可能なと列挙子の両方として機能できるようになります。The enumerable class implements both the enumerable interfaces and the enumerator interfaces, enabling it to serve as both an enumerable and an enumerator. GetEnumerator メソッドが初めて呼び出されたときに、列挙可能なオブジェクト自体が返されます。The first time the GetEnumerator method is invoked, the enumerable object itself is returned. その後、列挙可能なオブジェクトの GetEnumeratorを呼び出すと、列挙可能なオブジェクトのコピーが返されます。Subsequent invocations of the enumerable object's GetEnumerator, if any, return a copy of the enumerable object. したがって、返される各列挙子には独自の状態があり、1つの列挙子の変更は別の列挙子に影響しません。Thus, each returned enumerator has its own state and changes in one enumerator will not affect another. Interlocked.CompareExchange メソッドは、スレッドセーフな操作を確実に行うために使用されます。The Interlocked.CompareExchange method is used to ensure thread-safe operation.

from パラメーターと to パラメーターは、列挙可能なクラスのフィールドに変換されます。The from and to parameters are turned into fields in the enumerable class. 反復子ブロックで from が変更されるため、各列挙子の from に与えられた初期値を保持するために、追加の __from フィールドが導入されます。Because from is modified in the iterator block, an additional __from field is introduced to hold the initial value given to from in each enumerator.

MoveNext メソッドは、__state0ときに呼び出されると、InvalidOperationException をスローします。The MoveNext method throws an InvalidOperationException if it is called when __state is 0. これにより、最初に GetEnumeratorを呼び出すことなく、列挙可能なオブジェクトを列挙子オブジェクトとして使用することが防止されます。This protects against use of the enumerable object as an enumerator object without first calling GetEnumerator.

次の例は、単純なツリークラスを示しています。The following example shows a simple tree class. Tree<T> クラスは、反復子を使用して、その GetEnumerator メソッドを実装します。The Tree<T> class implements its GetEnumerator method using an iterator. 反復子は、ツリーの要素を挿入順序で列挙します。The iterator enumerates the elements of the tree in infix order.

using System;
using System.Collections.Generic;

class Tree<T>: IEnumerable<T>
{
    T value;
    Tree<T> left;
    Tree<T> right;

    public Tree(T value, Tree<T> left, Tree<T> right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public IEnumerator<T> GetEnumerator() {
        if (left != null) foreach (T x in left) yield x;
        yield value;
        if (right != null) foreach (T x in right) yield x;
    }
}

class Program
{
    static Tree<T> MakeTree<T>(T[] items, int left, int right) {
        if (left > right) return null;
        int i = (left + right) / 2;
        return new Tree<T>(items[i], 
            MakeTree(items, left, i - 1),
            MakeTree(items, i + 1, right));
    }

    static Tree<T> MakeTree<T>(params T[] items) {
        return MakeTree(items, 0, items.Length - 1);
    }

    // The output of the program is:
    // 1 2 3 4 5 6 7 8 9
    // Mon Tue Wed Thu Fri Sat Sun

    static void Main() {
        Tree<int> ints = MakeTree(1, 2, 3, 4, 5, 6, 7, 8, 9);
        foreach (int i in ints) Console.Write("{0} ", i);
        Console.WriteLine();

        Tree<string> strings = MakeTree(
            "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun");
        foreach (string s in strings) Console.Write("{0} ", s);
        Console.WriteLine();
    }
}

GetEnumerator メソッドは、次に示すように、反復子ブロックのコードをカプセル化する、コンパイラによって生成される列挙子クラスのインスタンス化に変換できます。The GetEnumerator method can be translated into an instantiation of a compiler-generated enumerator class that encapsulates the code in the iterator block, as shown in the following.

class Tree<T>: IEnumerable<T>
{
    ...

    public IEnumerator<T> GetEnumerator() {
        return new __Enumerator1(this);
    }

    class __Enumerator1 : IEnumerator<T>, IEnumerator
    {
        Node<T> __this;
        IEnumerator<T> __left, __right;
        int __state;
        T __current;

        public __Enumerator1(Node<T> __this) {
            this.__this = __this;
        }

        public T Current {
            get { return __current; }
        }

        object IEnumerator.Current {
            get { return __current; }
        }

        public bool MoveNext() {
            try {
                switch (__state) {

                case 0:
                    __state = -1;
                    if (__this.left == null) goto __yield_value;
                    __left = __this.left.GetEnumerator();
                    goto case 1;

                case 1:
                    __state = -2;
                    if (!__left.MoveNext()) goto __left_dispose;
                    __current = __left.Current;
                    __state = 1;
                    return true;

                __left_dispose:
                    __state = -1;
                    __left.Dispose();

                __yield_value:
                    __current = __this.value;
                    __state = 2;
                    return true;

                case 2:
                    __state = -1;
                    if (__this.right == null) goto __end;
                    __right = __this.right.GetEnumerator();
                    goto case 3;

                case 3:
                    __state = -3;
                    if (!__right.MoveNext()) goto __right_dispose;
                    __current = __right.Current;
                    __state = 3;
                    return true;

                __right_dispose:
                    __state = -1;
                    __right.Dispose();

                __end:
                    __state = 4;
                    break;

                }
            }
            finally {
                if (__state < 0) Dispose();
            }
            return false;
        }

        public void Dispose() {
            try {
                switch (__state) {

                case 1:
                case -2:
                    __left.Dispose();
                    break;

                case 3:
                case -3:
                    __right.Dispose();
                    break;

                }
            }
            finally {
                __state = 4;
            }
        }

        void IEnumerator.Reset() {
            throw new NotSupportedException();
        }
    }
}

foreach ステートメントで使用されるコンパイラによって生成された一時要素は、列挙子オブジェクトの __left および __right フィールドにリフトされます。The compiler generated temporaries used in the foreach statements are lifted into the __left and __right fields of the enumerator object. 列挙子オブジェクトの __state フィールドは、例外がスローされた場合に正しい Dispose() メソッドが正しく呼び出されるように、慎重に更新されます。The __state field of the enumerator object is carefully updated so that the correct Dispose() method will be called correctly if an exception is thrown. 単純な foreach ステートメントを使用して、翻訳したコードを記述することはできないことに注意してください。Note that it is not possible to write the translated code with simple foreach statements.

非同期関数Async functions

async 修飾子を持つメソッド (メソッド) または匿名関数 (匿名関数式) は、非同期関数と呼ばれます。A method (Methods) or anonymous function (Anonymous function expressions) with the async modifier is called an async function. 一般に、 asyncという用語は、async 修飾子を持つ任意の種類の関数を記述するために使用されます。In general, the term async is used to describe any kind of function that has the async modifier.

非同期関数の仮パラメーターリストで ref または out パラメーターを指定すると、コンパイル時にエラーになります。It is a compile-time error for the formal parameter list of an async function to specify any ref or out parameters.

非同期メソッドのreturn_typevoid またはタスクの種類である必要があります。The return_type of an async method must be either void or a task type. タスクの種類は System.Threading.Tasks.TaskSystem.Threading.Tasks.Task<T>から構築された型です。The task types are System.Threading.Tasks.Task and types constructed from System.Threading.Tasks.Task<T>. 簡潔にするために、この章では、これらの型はそれぞれ TaskTask<T>として参照されています。For the sake of brevity, in this chapter these types are referenced as Task and Task<T>, respectively. タスクの種類を返す非同期メソッドは、タスクを返すと言います。An async method returning a task type is said to be task-returning.

タスクの種類の正確な定義は実装で定義されていますが、言語の観点から見ると、タスクの種類は [未完了]、[成功]、または [失敗] のいずれかの状態になります。The exact definition of the task types is implementation defined, but from the language's point of view a task type is in one of the states incomplete, succeeded or faulted. エラーが発生したタスクは、関連する例外を記録します。A faulted task records a pertinent exception. Succeeded Task<T>T型の結果を記録します。A succeeded Task<T> records a result of type T. タスクの種類は待機可能であるため、await 式 (await 式) のオペランドにすることができます。Task types are awaitable, and can therefore be the operands of await expressions (Await expressions).

非同期関数呼び出しでは、その本体で await 式 (await 式) を使って評価を中断できます。An async function invocation has the ability to suspend evaluation by means of await expressions (Await expressions) in its body. 評価は、再開デリゲートによって、中断 await 式の時点で後で再開される場合があります。Evaluation may later be resumed at the point of the suspending await expression by means of a resumption delegate. 再開デリゲートの型は System.Actionであり、呼び出されると、非同期関数呼び出しの評価は、中断した await 式から再開されます。The resumption delegate is of type System.Action, and when it is invoked, evaluation of the async function invocation will resume from the await expression where it left off. 非同期関数呼び出しの現在の呼び出し元は、関数呼び出しが中断されていない場合は元の呼び出し元、それ以外の場合は再開デリゲートの最新の呼び出し元です。The current caller of an async function invocation is the original caller if the function invocation has never been suspended, or the most recent caller of the resumption delegate otherwise.

タスクを返す非同期関数の評価Evaluation of a task-returning async function

タスクを返す非同期関数を呼び出すと、返されたタスクの型のインスタンスが生成されます。Invocation of a task-returning async function causes an instance of the returned task type to be generated. これは、async 関数のreturn タスクと呼ばれます。This is called the return task of the async function. タスクは、最初は不完全な状態です。The task is initially in an incomplete state.

非同期関数本体は、(await 式に到達することによって) 中断されるか終了するまで評価されます。また、制御が戻りタスクと共に呼び出し元に返されます。The async function body is then evaluated until it is either suspended (by reaching an await expression) or terminates, at which point control is returned to the caller, along with the return task.

非同期関数の本体が終了すると、返されるタスクは不完全な状態から移動します。When the body of the async function terminates, the return task is moved out of the incomplete state:

  • 関数本体が return ステートメントまたは本体の末尾に到達した結果として終了した場合、結果の値は、succeeded タスクに記録されます。これは succeeded 状態になります。If the function body terminates as the result of reaching a return statement or the end of the body, any result value is recorded in the return task, which is put into a succeeded state.
  • キャッチされていない例外 (throw ステートメント) の結果として関数本体が終了した場合、例外はエラー状態になるリターンタスクに記録されます。If the function body terminates as the result of an uncaught exception (The throw statement) the exception is recorded in the return task which is put into a faulted state.

Void を返す非同期関数の評価Evaluation of a void-returning async function

非同期関数の戻り値の型が void場合、次のように評価が異なります。タスクが返されないため、関数は、現在のスレッドの同期コンテキストに対して完了と例外を通信します。If the return type of the async function is void, evaluation differs from the above in the following way: Because no task is returned, the function instead communicates completion and exceptions to the current thread's synchronization context. 同期コンテキストの正確な定義は実装に依存しますが、現在のスレッドが実行されている "where" の表現です。The exact definition of synchronization context is implementation-dependent, but is a representation of "where" the current thread is running. Void を返す非同期関数の評価が開始されるか、正常に完了するか、キャッチされていない例外がスローされると、同期コンテキストに通知されます。The synchronization context is notified when evaluation of a void-returning async function commences, completes successfully, or causes an uncaught exception to be thrown.

これにより、コンテキストは、その下で実行されている void を返す非同期関数の数を追跡し、その中で例外を伝達する方法を決定できます。This allows the context to keep track of how many void-returning async functions are running under it, and to decide how to propagate exceptions coming out of them.