値型 (C# リファレンス)

C# 型の 2 つの主なカテゴリは、値型参照型です。 値型の変数には、その型のインスタンスが含まれます。 これは、その型のインスタンスへの参照を含む参照型の変数とは異なります。 既定では、代入時、引数がメソッドに渡され、メソッドの結果が返され、変数値がコピーされます。 値型の変数の場合、対応する型のインスタンスがコピーされます。 次の例は、その動作を示します。

using System;

public struct MutablePoint
{
    public int X;
    public int Y;

    public MutablePoint(int x, int y) => (X, Y) = (x, y);

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

public class Program
{
    public static void Main()
    {
        var p1 = new MutablePoint(1, 2);
        var p2 = p1;
        p2.Y = 200;
        Console.WriteLine($"{nameof(p1)} after {nameof(p2)} is modified: {p1}");
        Console.WriteLine($"{nameof(p2)}: {p2}");

        MutateAndDisplay(p2);
        Console.WriteLine($"{nameof(p2)} after passing to a method: {p2}");
    }

    private static void MutateAndDisplay(MutablePoint p)
    {
        p.X = 100;
        Console.WriteLine($"Point mutated in a method: {p}");
    }
}
// Expected output:
// p1 after p2 is modified: (1, 2)
// p2: (1, 200)
// Point mutated in a method: (100, 200)
// p2 after passing to a method: (1, 200)

前の例のとおり、値型変数に対する操作は、その変数に格納されている値型のインスタンスのみに影響します。

値型に参照型のデータ メンバーが含まれている場合は、値型のインスタンスがコピーされるとき、その参照型のインスタンスへの参照のみがコピーされます。 コピーと元の値型のインスタンスの両方が、同じ参照型のインスタンスにアクセスできます。 次の例は、その動作を示します。

using System;
using System.Collections.Generic;

public struct TaggedInteger
{
    public int Number;
    private List<string> tags;

    public TaggedInteger(int n)
    {
        Number = n;
        tags = new List<string>();
    }

    public void AddTag(string tag) => tags.Add(tag);

    public override string ToString() => $"{Number} [{string.Join(", ", tags)}]";
}

public class Program
{
    public static void Main()
    {
        var n1 = new TaggedInteger(0);
        n1.AddTag("A");
        Console.WriteLine(n1);  // output: 0 [A]

        var n2 = n1;
        n2.Number = 7;
        n2.AddTag("B");

        Console.WriteLine(n1);  // output: 0 [A, B]
        Console.WriteLine(n2);  // output: 7 [A, B]
    }
}

注意

ご自分のコードをエラーがより発生しにくく、より堅牢にするには、変更できない値型を定義して使用します。 この記事では、デモンストレーションの目的でのみ、変更可能な値型を使用します。

値型と型制約の種類

値型には、次の 2 種類のいずれかを指定できます。

  • データと関連機能をカプセル化する構造体の型
  • 名前付き定数のセットによって定義され、選択肢または選択肢の組み合わせを表す、列挙型

null 許容値型 T? は、基になる値型のすべての値 T と、追加の null 値を表します。 値型の変数には、Null 許容値型でない限り null を割り当てることはできません。

struct 制約を使用して、型パラメーターが null 非許容値型であることを指定できます。 構造体と列挙型の型は、どちらも struct 制約を満たしています。 C# 7.3 以降、基底クラス制約 (列挙の制約と呼ばれます) で System.Enum を使用して、型パラメーターが列挙型であることを指定できます。

組み込みの値型

C# には、単純型 とも呼ばれる次の組み込み値型が用意されています。

すべての単純型は構造体型で、それらには他の構造体型とは異なる特定の追加操作があります。

  • 単純型の値の指定には、リテラルを使用できます。 たとえば、'A'char 型のリテラルで、2001int 型のリテラルです。

  • 単純型の定数は、const キーワードを使用して宣言できます。 他の構造体型の定数は使用できません。

  • オペランドがすべて単純型の定数の定数式は、コンパイル時に評価されます。

C# は C# 7.0 以降で、値のタプルをサポートしています。 値のタプルは単純型ではない値型です。

C# 言語仕様

詳細については、「C# 言語仕様」の次のセクションを参照してください。

関連項目