基礎から学ぶC#入門 90日コース | クラス・インスタンス・設計 - Day 37:static

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 37 のゴールと全体像

Day 37 のテーマは static です。 ここまで「インスタンス(オブジェクト)」を中心に見てきましたが、 今日は少し視点を変えて、

  • static
  • クラスメンバー
  • インスタンスメンバー
  • staticメソッド

というキーワードを通して、

「オブジェクトを作らなくても使えるもの」

を理解していきます。

雑誌の記事を読むような気持ちで、 「クラス全体で共有するもの」と「インスタンスごとに違うもの」の違いを、 ゆっくり整理していきましょう。

インスタンスメンバーとクラスメンバーの違い

まずはインスタンスメンバーのおさらい

これまでたくさん書いてきた、

  • フィールド
  • プロパティ
  • メソッド

は、基本的に インスタンスメンバー でした。

インスタンスメンバーとは、

「インスタンス(オブジェクト)ごとに別々の値や動きを持つメンバー」

のことです。

例として、Person クラスを見てみます。

class Person
{
    // インスタンスごとに違う値を持つプロパティ
    public string Name { get; set; }
    public int Age { get; set; }

    // インスタンスごとに動くメソッド
    public void Introduce()
    {
        Console.WriteLine($"こんにちは、{Name} です。年齢は {Age} 歳です。");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person p1 = new Person { Name = "太郎", Age = 20 };
        Person p2 = new Person { Name = "花子", Age = 25 };

        p1.Introduce(); // 太郎の情報で動く
        p2.Introduce(); // 花子の情報で動く

        Console.ReadLine();
    }
}
C#

ここでは、

  • p1p2 は別々のインスタンス
  • NameAge の値もインスタンスごとに違う
  • Introduce() の結果もインスタンスごとに違う

という状態になっています。

これが「インスタンスメンバー」です。

クラスメンバーとは何か

一方で、クラスメンバー は、

「クラス全体で共有されるメンバー」

です。

インスタンスごとに違うのではなく、 「そのクラスに属するものはみんな同じ値を共有する」 というイメージです。

クラスメンバーを作るために使うのが、 今日の主役である static です。

static の基本イメージ

「クラスに属するもの」にするキーワード

static は、

「このメンバーはインスタンスではなく、クラスに属する」

という意味のキーワードです。

例えば、Person クラスに「人数カウンタ」を付けてみます。

class Person
{
    // クラス全体で共有する人数カウンタ(static フィールド)
    public static int Count = 0;

    public string Name { get; set; }
    public int Age { get; set; }

    public Person()
    {
        // インスタンスが生成されるたびに、人数カウンタを増やす
        Count++;
    }

    public void Introduce()
    {
        Console.WriteLine($"こんにちは、{Name} です。年齢は {Age} 歳です。");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Person p1 = new Person { Name = "太郎", Age = 20 };
        Person p2 = new Person { Name = "花子", Age = 25 };
        Person p3 = new Person { Name = "次郎", Age = 30 };

        // static フィールドは、クラス名からアクセスします
        Console.WriteLine($"Person のインスタンス数: {Person.Count}");

        Console.ReadLine();
    }
}
C#

ここでのポイントは、

  • Countstatic なので、インスタンスではなくクラスに属している
  • Person が何個生成されても、Count は 1 つだけ
  • Person.Count という形で、クラス名からアクセスする

というところです。

重要ポイント:

  • static を付けると、「インスタンスごと」ではなく「クラス全体で共有」になります。
  • static メンバーには、インスタンスではなく クラス名 からアクセスします。

static フィールドとインスタンスフィールドの違い

並べて見ると分かりやすい

static あり/なしを並べてみると、違いがはっきりします。

class Sample
{
    // クラス全体で共有される static フィールド
    public static int StaticValue = 0;

    // インスタンスごとに違う値を持つフィールド
    public int InstanceValue = 0;
}

class Program
{
    static void Main(string[] args)
    {
        Sample s1 = new Sample();
        Sample s2 = new Sample();

        // インスタンスごとの値を変更
        s1.InstanceValue = 10;
        s2.InstanceValue = 20;

        // クラス全体の値を変更
        Sample.StaticValue = 100;

        Console.WriteLine($"s1.InstanceValue: {s1.InstanceValue}"); // 10
        Console.WriteLine($"s2.InstanceValue: {s2.InstanceValue}"); // 20

        Console.WriteLine($"Sample.StaticValue: {Sample.StaticValue}"); // 100

        Console.ReadLine();
    }
}
C#

ここでは、

  • InstanceValue はインスタンスごとに違う値を持つ
  • StaticValue はクラス全体で 1 つだけ存在する

という違いがあります。

重要ポイント:

  • 「インスタンスごとに違うべきもの」はインスタンスメンバー
  • 「クラス全体で共有したいもの」は static メンバー

というふうに、役割で使い分けるのがコツです。

static メソッドとは何か

「インスタンスを作らずに呼べるメソッド」

static は、メソッドにも付けることができます。 これが staticメソッド です。

staticメソッドは、

「インスタンスを作らずに、クラス名から直接呼び出せるメソッド」

です。

例として、簡単な計算用クラスを作ってみます。

class MathUtil
{
    // static メソッド:足し算
    public static int Add(int a, int b)
    {
        return a + b;
    }

    // static メソッド:掛け算
    public static int Multiply(int a, int b)
    {
        return a * b;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // インスタンスを作らずに、クラス名から直接呼び出せます
        int sum = MathUtil.Add(3, 5);
        int product = MathUtil.Multiply(4, 6);

        Console.WriteLine($"3 + 5 = {sum}");
        Console.WriteLine($"4 * 6 = {product}");

        Console.ReadLine();
    }
}
C#

ここでは、

  • MathUtil のインスタンスを作っていない
  • MathUtil.Add(...) / MathUtil.Multiply(...) と、クラス名から直接呼んでいる

という形になっています。

重要ポイント:

  • staticメソッドは「インスタンスに依存しない処理」を書く場所です。
  • そのメソッドが「特定のインスタンスの状態」を使わないなら、static にする候補になります。

static メソッドとインスタンスメソッドの違い

インスタンスの状態を使うかどうか

インスタンスメソッドと staticメソッドの違いは、

「インスタンスの状態(フィールドやプロパティ)を使うかどうか」

です。

例として、Circle クラスを考えてみます。

class Circle
{
    // 半径(インスタンスごとに違う)
    public double Radius { get; set; }

    // 円周率(クラス全体で共有してよい)
    public static double Pi = 3.14159265358979;

    // インスタンスメソッド:この円の面積を計算する
    public double GetArea()
    {
        return Pi * Radius * Radius;
    }

    // static メソッド:半径を渡して面積を計算するユーティリティ
    public static double CalcArea(double radius)
    {
        return Pi * radius * radius;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // インスタンスメソッドの例
        Circle c = new Circle { Radius = 10 };
        Console.WriteLine($"半径 10 の円の面積(インスタンスメソッド): {c.GetArea()}");

        // static メソッドの例
        double area = Circle.CalcArea(10);
        Console.WriteLine($"半径 10 の円の面積(static メソッド): {area}");

        Console.ReadLine();
    }
}
C#

ここでは、

  • GetArea() はインスタンスメソッド
    • Radius というインスタンスごとの値を使っている
  • CalcArea() は staticメソッド
    • 引数として半径を受け取り、インスタンスに依存しない形で計算している

という違いがあります。

重要ポイント:

  • 「このインスタンスの状態を使って処理する」ならインスタンスメソッド
  • 「インスタンスに依存せず、引数だけで処理できる」なら staticメソッド

というふうに、役割で使い分けると整理しやすいです。

Day 37 用の練習テンプレート

最後に、static とインスタンスの違いを練習するためのテンプレートを紹介します。

ログ出力ユーティリティの例

using System;

class Logger
{
    // ログの出力回数をクラス全体で共有する static フィールド
    public static int LogCount { get; private set; } = 0;

    // インスタンスごとに違う「名前」を持てるようにする
    public string Name { get; set; }

    public Logger(string name)
    {
        Name = name;
    }

    // インスタンスメソッド:このロガーの名前付きでログを出す
    public void Log(string message)
    {
        LogCount++; // クラス全体のログ回数を増やす
        Console.WriteLine($"[{Name}] {message}");
    }

    // static メソッド:現在のログ回数を表示する
    public static void ShowLogCount()
    {
        Console.WriteLine($"ログ出力回数: {LogCount}");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Logger appLogger = new Logger("App");
        Logger dbLogger = new Logger("DB");

        appLogger.Log("アプリケーションを開始しました。");
        dbLogger.Log("データベースに接続しました。");
        appLogger.Log("処理が完了しました。");

        // クラス名から static メソッドを呼び出す
        Logger.ShowLogCount();

        Console.ReadLine();
    }
}
C#

このテンプレートを眺めながら、

  • LogCount はクラス全体で共有されていること
  • Name はインスタンスごとに違うこと
  • Log() はインスタンスメソッドで、Name を使っていること
  • ShowLogCount() は staticメソッドで、クラス全体の状態だけを使っていること

を意識してみると、 static とインスタンスの違いがぐっとクリアになります。

Day 37 のまとめ

Day 37 では、

  • インスタンスメンバー = インスタンスごとに違う値や動きを持つメンバー
  • クラスメンバー = クラス全体で共有されるメンバー(static
  • static フィールド = クラス名からアクセスし、全インスタンスで共有される値
  • static メソッド = インスタンスを作らずに呼べる、インスタンスに依存しない処理

という流れで、 「クラス全体で共有するもの」と「インスタンスごとに違うもの」 を見分ける視点を育てました。

ぜひ、

  • 自分でクラスを 1 つ作って、「これは全体で共有したい」「これはインスタンスごとに違うべき」と考えてみる
  • インスタンスに依存しない処理を、staticメソッドとして切り出してみる
  • 「クラス名から呼ぶもの」と「インスタンスから呼ぶもの」を意識してコードを書いてみる

といった練習を通して、 static を 「ただのキーワード」ではなく、 クラスの役割を整理するための道具として、少しずつ自分の感覚に馴染ませていってください。

タイトルとURLをコピーしました