構造体型 (C# リファレンス)Structure types (C# reference)

"構造体型" (または "構造体型") とは、データおよび関連する機能をカプセル化できる値の型です。A structure type (or struct type) is a value type that can encapsulate data and related functionality. 構造体型を定義するには、struct キーワードを使用します。You use the struct keyword to define a structure type:

public struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public override string ToString() => $"({X}, {Y})";
}

構造体型には、"値のセマンティクス" があります。Structure types have value semantics. つまり、構造体型の変数には、型のインスタンスが含まれます。That is, a variable of a structure type contains an instance of the type. 既定では、変数値が代入時にコピーされ、引数がメソッドに渡され、メソッドの結果が返されます。By default, variable values are copied on assignment, passing an argument to a method, and returning a method result. 構造体型の変数の場合は、型のインスタンスがコピーされます。In the case of a structure-type variable, an instance of the type is copied. 詳細については、値の型に関するページを参照してください。For more information, see Value types.

通常は、構造体型を使用して、ほとんどまたはまったく動作を提供しない小さなデータ中心型を設計します。Typically, you use structure types to design small data-centric types that provide little or no behavior. たとえば、.NET では、構造体型を使用して数値 (整数実数の両方)、ブール値Unicode 文字時刻インスタンスが表現されます。For example, .NET uses structure types to represent a number (both integer and real), a Boolean value, a Unicode character, a time instance. 型の動作に重点を置いている場合は、class を定義することを検討してください。If you're focused on the behavior of a type, consider defining a class. クラス型には "参照セマンティクス" があります。Class types have reference semantics. つまり、クラス型の変数には、インスタンス自体ではなく、型のインスタンスへの参照が含まれています。That is, a variable of a class type contains a reference to an instance of the type, not the instance itself.

構造体型には値セマンティクスがあるため、"変更不可" の構造体型を定義することをお勧めします。Because structure types have value semantics, we recommend you to define immutable structure types.

readonly 構造体readonly struct

C# 7.2 以降では、構造体型が変更不可であることを宣言するには、readonly 修飾子を使用します。Beginning with C# 7.2, you use the readonly modifier to declare that a structure type is immutable:

public readonly struct Coords
{
    public Coords(double x, double y)
    {
        X = x;
        Y = y;
    }

    public double X { get; }
    public double Y { get; }

    public override string ToString() => $"({X}, {Y})";
}

readonly 構造体のすべてのデータ メンバーを、次のように読み取り専用にする必要があります。All data members of a readonly struct must be read-only as follows:

  • すべてのフィールド宣言には、readonly 修飾子が必要ですAny field declaration must have the readonly modifier
  • 自動的に実装されるプロパティも含めて、すべてのプロパティは、読み取り専用である必要がありますAny property, including auto-implemented ones, must be read-only

それにより、readonly 構造体のどのメンバーも構造体の状態を変更しないことが保証されます。That guarantees that no member of a readonly struct modifies the state of the struct.

注意

readonly 構造体でも、変更可能な参照型のデータ メンバーは、それ自身の状態を変更できます。In a readonly struct, a data member of a mutable reference type still can mutate its own state. たとえば、List<T> インスタンスを置き換えることはできませんが、新しい要素をそれに追加することはできます。For example, you can't replace a List<T> instance, but you can add new elements to it.

readonly インスタンス メンバーreadonly instance members

C# 8.0 以降では、readonly 修飾子を使用して、インスタンス メンバーで構造体の状態を変更しないことを宣言することもできます。Beginning with C# 8.0, you can also use the readonly modifier to declare that an instance member doesn't modify the state of a struct. 構造体の型全体を readonly として宣言できない場合は、readonly 修飾子を使用して、構造体の状態を変更しないインスタンス メンバーをマークします。If you can't declare the whole structure type as readonly, use the readonly modifier to mark the instance members that don't modify the state of the struct. readonly 構造体では、すべてのインスタンス メンバーは暗黙的に readonly です。In a readonly struct, every instance member is implicitly readonly.

readonly インスタンス メンバー内では、構造体のインスタンス フィールドに割り当てることはできません。Within a readonly instance member, you can't assign to structure's instance fields. ただし、readonly メンバーから非 readonly メンバーを呼び出すことができます。However, a readonly member can call a non-readonly member. その場合、コンパイラを使用して構造体インスタンスのコピーを作成し、そのコピーで非 readonly メンバーを呼び出します。In that case the compiler creates a copy of the structure instance and calls the non-readonly member on that copy. その結果、元の構造インスタンスは変更されません。As a result, the original structure instance is not modified.

通常、readonly 修飾子を次の種類のインスタンス メンバーに適用します。Typically, you apply the readonly modifier to the following kinds of instance members:

  • メソッド:methods:

    public readonly double Sum()
    {
        return X + Y;
    }
    

    System.Object で宣言されたメソッドをオーバーライドするメソッドに readonly 修飾子を適用することもできます。You can also apply the readonly modifier to methods that override methods declared in System.Object:

    public readonly override string ToString() => $"({X}, {Y})";
    
  • プロパティとインデクサー:properties and indexers:

    private int counter;
    public int Counter
    {
        readonly get => counter;
        set => counter = value;
    }
    

    プロパティまたはインデクサーの両方のアクセサーに readonly 修飾子を適用する必要がある場合は、プロパティまたはインデクサーの宣言でそれを適用します。If you need to apply the readonly modifier to both accessors of a property or indexer, apply it in the declaration of the property or indexer.

    注意

    プロパティの宣言に readonly 修飾子が存在するかどうかに関係なく、コンパイラによって自動実装プロパティget アクセサーが readonly として宣言されます。The compiler declares a get accessor of an auto-implemented property as readonly, regardless of presence of the readonly modifier in a property declaration.

readonly 修飾子を構造体型の静的メンバーに適用することはできません。You can't apply the readonly modifier to static members of a structure type.

パフォーマンスの最適化のためにコンパイラで readonly 修飾子を使用する場合があります。The compiler may make use of the readonly modifier for performance optimizations. 詳細については、「安全で効率的な C# コードを記述する」をご覧ください。For more information, see Write safe and efficient C# code.

構造体型の設計に関する制限事項Limitations with the design of a structure type

構造体型を設計する場合は、class 型と同じ機能を使用できますが、次の例外があります。When you design a structure type, you have the same capabilities as with a class type, with the following exceptions:

  • パラメーターなしのコンストラクターを宣言することはできません。You can't declare a parameterless constructor. すべての構造体型には、型の既定値を生成する暗黙的なパラメーターなしのコンストラクターが既に備わっています。Every structure type already provides an implicit parameterless constructor that produces the default value of the type.

  • インスタンス フィールドまたはプロパティを、それらの宣言で初期化することはできません。You can't initialize an instance field or property at its declaration. ただし、static または const フィールド、あるいは静的プロパティについては、それらの宣言で初期化することができます。However, you can initialize a static or const field or a static property at its declaration.

  • 構造体型のコンストラクターでは、型のすべてのインスタンス フィールドを初期化する必要があります。A constructor of a structure type must initialize all instance fields of the type.

  • 構造体型は、他のクラスまたは構造体型から継承することができないほか、クラスのベースとすることもできません。A structure type can't inherit from other class or structure type and it can't be the base of a class. ただし、構造体型では interfaces を実装することができます。However, a structure type can implement interfaces.

  • 構造体型内でファイナライザーを宣言することはできません。You can't declare a finalizer within a structure type.

構造体型のインスタンス化Instantiation of a structure type

C# では、宣言された変数を使用するには、事前にこれを初期化する必要があります。In C#, you must initialize a declared variable before it can be used. 構造体型の変数は (null 許容値型の変数でない限り) null とすることができないため、対応する型のインスタンスをインスタンス化する必要があります。Because a structure-type variable can't be null (unless it's a variable of a nullable value type), you must instantiate an instance of the corresponding type. それにはいくつかの方法があります。There are several ways to do that.

通常は、new 演算子を使用して適切なコンストラクターを呼び出すことによって、構造体型をインスタンス化します。Typically, you instantiate a structure type by calling an appropriate constructor with the new operator. すべての構造体型に、少なくとも 1 つのコンストラクターがあります。Every structure type has at least one constructor. それは暗黙的なパラメーターなしのコンストラクターであり、型の既定値を生成するものです。That's an implicit parameterless constructor, which produces the default value of the type. また、既定の値式を使用して、型の既定値を生成することもできます。You can also use a default value expression to produce the default value of a type.

構造体型のすべてのインスタンス フィールドにアクセスできる場合は、それを new 演算子なしでインスタンス化することもできます。If all instance fields of a structure type are accessible, you can also instantiate it without the new operator. その場合は、インスタンスを初めて使用する前に、すべてのインスタンス フィールドを初期化する必要があります。In that case you must initialize all instance fields before the first use of the instance. その方法を次の例に示します。The following example shows how to do that:

public static class StructWithoutNew
{
    public struct Coords
    {
        public double x;
        public double y;
    }

    public static void Main()
    {
        Coords p;
        p.x = 3;
        p.y = 4;
        Console.WriteLine($"({p.x}, {p.y})");  // output: (3, 4)
    }
}

組み込みの値型の場合は、対応するリテラルを使用して型の値を指定します。In the case of the built-in value types, use the corresponding literals to specify a value of the type.

構造体型の変数を参照渡しするPassing structure-type variables by reference

構造体型の変数を引数としてメソッドに渡す場合、またはメソッドから構造体型の値を返す場合は、構造体型のインスタンス全体がコピーされます。When you pass a structure-type variable to a method as an argument or return a structure-type value from a method, the whole instance of a structure type is copied. これは、大規模な構造体型を必要とするハイパフォーマンスのシナリオの場合、ご利用のコードのパフォーマンスに影響を与える可能性があります。That can affect the performance of your code in high-performance scenarios that involve large structure types. 値のコピーを回避するには、構造体型の変数を参照渡しします。You can avoid value copying by passing a structure-type variable by reference. 引数を参照渡しする必要があることを示すには、refout、または in のメソッド パラメーター修飾子を使用します。Use the ref, out, or in method parameter modifiers to indicate that an argument must be passed by reference. メソッドの結果を参照渡しによって返すには、ref 戻り値を使用します。Use ref returns to return a method result by reference. 詳細については、「安全で効率的な C# コードを記述する」をご覧ください。For more information, see Write safe and efficient C# code.

ref 構造体ref struct

C# 7.2 以降、ref 修飾子は、構造体型の宣言内で使用できます。Beginning with C# 7.2, you can use the ref modifier in the declaration of a structure type. ref 構造体型のインスタンスはスタック上に割り当てられます。マネージド ヒープにエスケープすることはできません。Instances of a ref struct type are allocated on the stack and can't escape to the managed heap. これを確実にするために、コンパイラでは次のように ref 構造体型の使用が制限されます。To ensure that, the compiler limits the usage of ref struct types as follows:

  • ref 構造体を配列の要素型にすることはできません。A ref struct can't be the element type of an array.
  • ref 構造体をクラスまたは非 ref 構造体のフィールドの宣言型にすることはできません。A ref struct can't be a declared type of a field of a class or a non-ref struct.
  • ref 構造体ではインターフェイスを実装できません。A ref struct can't implement interfaces.
  • ref 構造体を System.ValueType または System.Object にボックス化することはできません。A ref struct can't be boxed to System.ValueType or System.Object.
  • ref 構造体を型引数にすることはできません。A ref struct can't be a type argument.
  • ref 構造体変数をラムダ式またはローカル関数でキャプチャすることはできません。A ref struct variable can't be captured by a lambda expression or a local function.
  • ref 構造体変数を async メソッド内で使用することはできません。A ref struct variable can't be used in an async method. ただし、Task または Task<TResult> を返す場合など、同期メソッドで ref 構造体変数を使用することはできます。However, you can use ref struct variables in synchronous methods, for example, in those that return Task or Task<TResult>.
  • ref 構造体変数を反復子内で使用することはできません。A ref struct variable can't be used in iterators.

通常、ref 構造体型のデータ メンバーも含む型が必要な場合は、ref 構造体型を定義します。Typically, you define a ref struct type when you need a type that also includes data members of ref struct types:

public ref struct CustomRef
{
    public bool IsValid;
    public Span<int> Inputs;
    public Span<int> Outputs;
}

ref 構造体を readonly として宣言するには、型宣言内で readonly 修飾子と ref 修飾子を組み合わせます (readonly 修飾子は ref 修飾子よりも前にある必要があります)。To declare a ref struct as readonly, combine the readonly and ref modifiers in the type declaration (the readonly modifier must come before the ref modifier):

public readonly ref struct ConversionRequest
{
    public ConversionRequest(double rate, ReadOnlySpan<double> values)
    {
        Rate = rate;
        Values = values;
    }

    public double Rate { get; }
    public ReadOnlySpan<double> Values { get; }
}

.NET では、ref 構造体の例として System.Span<T>System.ReadOnlySpan<T> があります。In .NET, examples of a ref struct are System.Span<T> and System.ReadOnlySpan<T>.

変換Conversions

どの構造体型にも (ref 構造体型を除く)、System.ValueType 型と System.Object 型の間にボックス化およびボックス化解除の変換が存在します。For any structure type (except ref struct types), there exist boxing and unboxing conversions to and from the System.ValueType and System.Object types. また、構造体型と、これによって実装されるインターフェイスとの間にも、ボックス化とボックス化解除の変換が存在します。There exist also boxing and unboxing conversions between a structure type and any interface that it implements.

C# 言語仕様C# language specification

詳細については、C# 言語仕様の「構造体」セクションを参照してください。For more information, see the Structs section of the C# language specification.

C# 7.2 以降で導入された機能の詳細については、次の機能の提案に関するメモを参照してください。For more information about features introduced in C# 7.2 and later, see the following feature proposal notes:

関連項目See also