C Sharp/値型

出典: フリー教科書『ウィキブックス(Wikibooks)』

値型[編集]

C#には、値型と参照型の2つの主要な型があります。値型は変数がその値自体を保持し、参照型は変数がオブジェクトへの参照を保持します。ここでは、値型に焦点を当てて詳細に説明します。

値型の種類:[編集]

  1. 組み込みの値型:
    • int, double, bool, char などのプリミティブな型がこれに該当します。
    • これらの型はメモリ上のスタックに直接的に保存されます。
  2. 構造体 (Structures):
    • struct キーワードを使用して定義されます。
    • class とは異なり、値型として扱われます。
    • struct はユーザー定義のデータ型を作成する際に使用され、値型としての特性を持ちます。
  3. 列挙型:
    • enum キーワードを使用して定義されます。
    • 整数値にシンボリックな名前に対応付けする
    • 関連する定数値をまとめて扱いやすくする

値型の特徴:[編集]

  1. スタックメモリに保存される:
    • 値型の変数は通常、メモリ上のスタックに直接的に保存されます。
    • メモリ管理は効率的であり、スタックに直接値を保存するため、参照型よりも高速です。
  2. デフォルトでnullを持たない:
    • 値型の変数は、基本的にデフォルト値で初期化されます。例えば、intの場合は0boolの場合はfalseです。
  3. プリミティブな演算子を使用可能:
    • 値型は、プリミティブな演算子(加算、減算、比較など)を使用して直接操作できます。
  4. コピーが生成される:
    • 値型の変数を別の変数に代入すると、新しいコピーが作成されます。
    • これにより、変数間での値の変更は互いに影響を受けません。

値型の例:[編集]

// 組み込みの値型
int number = 10;
char character = 'A';
bool flag = true;
double value = 3.14;

// 構造体
public struct Point {
  public int X;
  public int Y;
}

Point point = new Point();
point.X = 5;
point.Y = 10;

これらの値型は、データを効率的に処理し、メモリを効果的に使用するための便利な手段を提供します。 ただし、大きなデータや複雑なデータ構造が必要な場合は、参照型(クラスなど)を検討することも重要です。

構造体[編集]

C#における struct(構造体)は、値型の一つで、データの単純な構造を表現するために使用されます。structは、クラスと似た構文を持ちますが、いくつかの重要な違いがあります。

構造体(struct)の特徴
  1. 値型:
    • 構造体は値型であり、参照型(クラス)とは異なり、値そのものを保持します。そのため、メモリのスタック領域に直接保存されます。
  2. ボックス化されない:
    • 構造体はボックス化(Boxing)されないため、ヒープ上にオブジェクトとして保存されることはありません。そのため、参照型(クラス)と比較してメモリ効率が高いです。
  3. デフォルトでパブリック:
    • 構造体のメンバーはデフォルトでパブリックになります。しかし、構造体自体は継承できず、他の構造体またはクラスから派生することはできません。
  4. デフォルトのコンストラクタ:
    • パラメーターなしのデフォルトコンストラクタを自動的に持ちます。ただし、自分自身のコンストラクタを定義することも可能です。
  5. イミュータブル(不変)な設計を推奨:
    • 一般的に、構造体はイミュータブルな設計(変更不能な状態)を推奨します。
構造体の例
public struct Point {
  public int X;
  public int Y;

  // パラメーター付きコンストラクタ
  public Point(int x, int y) {
    X = x;
    Y = y;
  }

  // メソッドの定義
  public void Display() {
    Console.WriteLine($"X: {X}, Y: {Y}");
  }
}

構造体は、データの軽量な保持や処理のために使用されます。特に、小さなデータ構造やイミュータブルなオブジェクトの表現に適しています。しかし、大量のデータや複雑な振る舞いが必要な場合は、クラスの使用を検討することが推奨されます。

列挙型[編集]

列挙型(Enum)はC#における値型の一つです。列挙型は、整数値をシンボリックな名前に対応付けたり、関連する定数値をまとめたりするために使用されます。

初期のC#では、列挙型は基本的な整数型(int)のみを持つことができました。

基本の列挙型[編集]

using System;

// 単純な列挙型の定義
public enum Days {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
}

class Program {
  static void Main() {
    Days today = Days.Wednesday; // 列挙型の要素を変数に代入

    Console.WriteLine($"Today is {today}"); // 列挙型の要素を表示

    // 列挙型の要素を比較
    if (today == Days.Wednesday) {
      Console.WriteLine("It's Wednesday!");
    }
  }
}

このコードは、C# 3.0での単純な列挙型の使い方を示しています。列挙型は、コードをわかりやすくするために定数値をシンボルに置き換えるのに役立ちます。この例では、列挙型 Days を使用して特定の曜日を表しています。

フラグ属性[編集]

その後のバージョンで、列挙型は機能の面で進化しました。C# 7.0から、列挙型にフラグ属性を追加することができるようになりました。これにより、列挙型の各定数がビットごとのフラグとして扱われ、複数の定数を組み合わせて1つの値として表現することができます。

[Flags]
public enum DaysOfWeek {
  None = 0,
    Sunday = 1,
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thursday = 16,
    Friday = 32,
    Saturday = 64
}

// フラグを組み合わせて利用する例
DaysOfWeek weekend = DaysOfWeek.Saturday | DaysOfWeek.Sunday;

列挙型に対するパターンマッチング[編集]

また、C# 8.0でenumに対するパターンマッチングのサポートが追加されました。これにより、switch 文や is 構文を使用して列挙型の値を簡潔にチェックすることができるようになりました。

DaysOfWeek day = DaysOfWeek.Monday;

switch (day) {
case DaysOfWeek.Saturday or DaysOfWeek.Sunday:
  Console.WriteLine("It's weekend!");
  break;
case DaysOfWeek.Monday:
  Console.WriteLine("It's Monday...");
  break;
default:
  Console.WriteLine("It's a weekday.");
  break;
}

列挙型と拡張メソッド[編集]

列挙型自体に直接メソッドを定義することはできませんが、C#では列挙型に対して拡張メソッドを定義することができます。

拡張メソッドは、既存のクラスや型に新しいメソッドを追加するための機能です。これにより、列挙型にもメソッドを追加して、より豊かな機能を提供することができます。

例えば、以下は DaysOfWeek 列挙型に対して拡張メソッド IsWeekend() を追加する例です。

using System;

public enum DaysOfWeek {
  Sunday,
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday
}

public static class DaysOfWeekExtensions {
  public static bool IsWeekend(this DaysOfWeek day) {
    return day == DaysOfWeek.Saturday || day == DaysOfWeek.Sunday;
  }
}

class Program {
  static void Main() {
    DaysOfWeek today = DaysOfWeek.Saturday;

    Console.WriteLine(today.IsWeekend()); // 拡張メソッドを呼び出して週末かどうかをチェック
  }
}

このように、拡張メソッドを使用すると、列挙型にメソッドを追加して列挙型の振る舞いを拡張することができます。ただし、拡張メソッドは静的クラスの中に定義される必要があり、列挙型自体に直接メソッドを追加することはできません。