C#の静的とは?staticの意味・使い方・インスタンスとの違いを初心者向けに解説

はじめに

C#を学び始めると、staticというキーワードをよく見かけます。特にMainメソッドや、Console.WriteLine()Math.Max()などを使うときに、実はstaticが関係しています。

しかし初心者にとって、staticは少し理解しづらい概念です。「静的とは何か」「インスタンスと何が違うのか」「いつstaticを使えばよいのか」が分からないまま使っている人も多いでしょう。

この記事では、C#の静的、つまりstaticの意味や使い方を、初心者にも分かりやすく解説します。staticメソッド、staticフィールド、staticプロパティ、staticクラス、staticコンストラクターまで、サンプルコードを使いながら順番に見ていきましょう。

1. C#の静的とは?staticの意味を初心者向けに解説

C#における「静的」とは、英語のstaticを日本語にした言葉です。

staticは、簡単に言うと「クラスそのものに属するもの」を表します。通常、C#ではクラスからオブジェクトを作成して、そのオブジェクトを通してメソッドや変数を使います。しかしstaticが付いたメンバーは、オブジェクトを作らなくてもクラス名から直接使うことができます。

たとえば、C#でよく使うMathクラスのMaxメソッドはstaticメソッドです。

C#
int result = Math.Max(10, 20);
Console.WriteLine(result);

このコードでは、new Math()のようにインスタンスを作っていません。Math.Max()のように、クラス名から直接呼び出しています。これがstaticの代表的な使い方です。

1-1. staticは「インスタンスではなくクラスに属する」ことを表すキーワード

C#では、クラスを設計図、インスタンスを設計図から作られた実物として考えると分かりやすくなります。

たとえば、Personクラスがあるとします。

C#
class Person
{
public string Name;

public void SayHello()
{
Console.WriteLine($"こんにちは、{Name}です。");
}
}

このクラスを使うには、通常は次のようにインスタンスを作ります。

C#
Person person = new Person();
person.Name = "田中";
person.SayHello();

このNameSayHello()は、作成されたpersonというインスタンスに属しています。一方、staticを付けると、そのメンバーは個別のインスタンスではなく、クラスそのものに属します。

C#
class AppInfo
{
public static string Version = "1.0.0";
}

この場合、次のようにクラス名から直接アクセスできます。

C#
Console.WriteLine(AppInfo.Version);

つまりstaticは、「このデータや処理は、個別のオブジェクトごとに持つものではなく、クラス全体で共通して使うものです」と表すキーワードです。

1-2. 「静的」と「動的」の違いをプログラムの生成タイミングで理解する

「静的」と聞くと難しく感じるかもしれませんが、ポイントは「いつ用意されるか」です。

staticメンバーは、プログラムの実行中にクラス単位で管理されます。インスタンスを作成しなくても使えるため、個別のオブジェクトに依存しません。

一方、インスタンスメンバーは、newによってオブジェクトが作られた後に、そのオブジェクトごとに使えるようになります。

C#
class Sample
{
public static int StaticValue = 100;
public int InstanceValue = 200;
}

使い方は次のように違います。

C#
Console.WriteLine(Sample.StaticValue);

Sample sample = new Sample();
Console.WriteLine(sample.InstanceValue);

StaticValueはクラス名のSampleから呼び出しています。一方、InstanceValuenew Sample()で作成したインスタンスから呼び出しています。

1-3. C#でstaticを使う主な場面

C#でstaticを使う主な場面は、次のようなケースです。

使う場面
共通処理をまとめる文字列変換、計算処理、日付処理
定数や設定値を持つアプリ名、バージョン、共通メッセージ
インスタンスに依存しない処理を作るMath.Max()のような計算メソッド
プログラムの開始点を定義するstatic void Main()
全体で共有する値を持つ作成件数のカウンターなど

staticは便利ですが、何でもstaticにすればよいわけではありません。個別の状態を持つ処理には、インスタンスを使う方が適しています。

2. staticとインスタンスの違い

staticを理解するには、インスタンスとの違いを押さえることが大切です。

C#では、通常クラスからオブジェクトを作成して処理を行います。この作成されたオブジェクトがインスタンスです。一方、staticはインスタンスを作らずに使える仕組みです。

2-1. インスタンスとは何か

インスタンスとは、クラスという設計図から作られた実体のことです。

たとえば、次のようなCarクラスがあるとします。

C#
class Car
{
public string Color;

public void Drive()
{
Console.WriteLine($"{Color}の車が走ります。");
}
}

このクラスからインスタンスを作るには、newを使います。

C#
Car car1 = new Car();
car1.Color = "赤";

Car car2 = new Car();
car2.Color = "青";

car1.Drive();
car2.Drive();

実行すると、car1car2はそれぞれ別の色を持つ別々のインスタンスになります。

赤の車が走ります。
青の車が走ります。

このように、インスタンスメンバーはオブジェクトごとに異なる値を持てます。

2-2. staticメンバーとインスタンスメンバーの違い

staticメンバーはクラスに属し、インスタンスメンバーはオブジェクトに属します。

C#
class User
{
public static int Count;
public string Name;
}

この例では、CountはstaticフィールドなのでUserクラス全体で共有されます。一方、Nameはインスタンスフィールドなので、作成されたユーザーごとに別々の値を持ちます。

C#
User user1 = new User();
user1.Name = "佐藤";

User user2 = new User();
user2.Name = "鈴木";

User.Count = 2;

Console.WriteLine(user1.Name);
Console.WriteLine(user2.Name);
Console.WriteLine(User.Count);

Nameuser1user2で別々ですが、CountUserクラスに対して1つだけ存在します。

2-3. メモリ上の扱いと共有範囲の違い

staticメンバーは、基本的にクラス単位で1つだけ管理されます。複数のインスタンスを作っても、staticフィールドは共有されます。

一方、インスタンスメンバーはインスタンスごとに別々に管理されます。

C#
class Counter
{
public static int StaticCount;
public int InstanceCount;
}

次のコードを見てください。

C#
Counter a = new Counter();
Counter b = new Counter();

a.InstanceCount++;
b.InstanceCount++;

Counter.StaticCount++;
Counter.StaticCount++;

Console.WriteLine(a.InstanceCount);
Console.WriteLine(b.InstanceCount);
Console.WriteLine(Counter.StaticCount);

実行結果は次のようになります。

1
1
2

InstanceCountabで別々に管理されるため、それぞれ1です。一方、StaticCountはクラスで共有されるため、2になります。

2-4. staticはオブジェクトをnewしなくても使える

staticの大きな特徴は、newしなくても使えることです。

C#
class Calculator
{
public static int Add(int a, int b)
{
return a + b;
}
}

このメソッドは次のように呼び出せます。

C#
int result = Calculator.Add(3, 5);
Console.WriteLine(result);

Calculator calculator = new Calculator();のようにインスタンスを作る必要はありません。

ただし、これは「staticなら何でも便利」という意味ではありません。インスタンスごとに異なる状態が必要な場合は、staticではなく通常のインスタンスメンバーを使うべきです。

2-5. 比較表で理解するstaticとインスタンスの違い

項目staticインスタンス
所属先クラスオブジェクト
呼び出し方クラス名.メンバー名変数名.メンバー名
newの必要性不要必要
値の持ち方クラス全体で共有インスタンスごとに個別
向いている用途共通処理、定数、ユーティリティ個別の状態を持つ処理
Math.Max()person.Name

staticは「全体で1つ」、インスタンスは「オブジェクトごとに1つ」と覚えると理解しやすいです。

3. C#でstaticを使う基本構文

C#では、フィールド、プロパティ、メソッド、クラス、コンストラクターなどにstaticを付けることができます。

ここでは、基本的な書き方を見ていきましょう。

3-1. staticフィールドの書き方

staticフィールドは、クラス全体で共有される変数です。

C#
class Sample
{
public static int Count = 0;
}

呼び出すときは、クラス名を使います。

C#
Sample.Count++;
Console.WriteLine(Sample.Count);

staticフィールドは、すべてのインスタンスで共有されます。そのため、アプリケーション全体で共通して使う値を管理できます。

3-2. staticプロパティの書き方

staticプロパティは、クラスに属するプロパティです。

C#
class AppSettings
{
public static string AppName { get; set; } = "Sample App";
}

使い方は次のとおりです。

C#
Console.WriteLine(AppSettings.AppName);

AppSettings.AppName = "New App";
Console.WriteLine(AppSettings.AppName);

staticプロパティは、外部からアクセスする値をプロパティとして管理したいときに使います。

3-3. staticメソッドの書き方

staticメソッドは、インスタンスを作らなくても呼び出せるメソッドです。

C#
class Calculator
{
public static int Add(int a, int b)
{
return a + b;
}
}

呼び出し方は次のようになります。

C#
int answer = Calculator.Add(10, 20);
Console.WriteLine(answer);

引数だけで処理が完結する計算メソッドなどは、staticメソッドに向いています。

3-4. クラス名からstaticメンバーを呼び出す方法

staticメンバーは、基本的に次の形で呼び出します。

C#
クラス名.メンバー名

たとえば、次のようなクラスがあるとします。

C#
class Message
{
public static string Text = "こんにちは";

public static void Show()
{
Console.WriteLine(Text);
}
}

呼び出しは次のようにします。

C#
Console.WriteLine(Message.Text);
Message.Show();

staticメンバーはインスタンスではなくクラスに属しているため、クラス名から呼ぶのが自然です。

3-5. 初心者が混乱しやすい呼び出し方の注意点

初心者がよく混乱するのは、staticメンバーをインスタンスから呼び出そうとするケースです。

C#
class Sample
{
public static void Show()
{
Console.WriteLine("staticメソッドです");
}
}

次のような書き方は避けるべきです。

C#
Sample sample = new Sample();
sample.Show();

staticメソッドはインスタンスではなくクラスに属するため、次のように書きます。

C#
Sample.Show();

C#では、staticメンバーをインスタンス参照で呼び出すとエラーや警告の原因になります。staticは「クラス名から呼ぶ」と覚えておきましょう。

4. staticメソッドの使い方

staticメソッドは、C#のstaticの中でも特によく使われます。処理がオブジェクトの状態に依存しない場合、staticメソッドとして定義できます。

4-1. staticメソッドとは

staticメソッドとは、クラスに属するメソッドです。インスタンスを作らなくても呼び出せます。

たとえば、2つの数値を足すだけの処理は、特定のオブジェクト状態を必要としません。

C#
class Calculator
{
public static int Add(int x, int y)
{
return x + y;
}
}

このような処理はstaticメソッドに向いています。

C#
int result = Calculator.Add(5, 7);
Console.WriteLine(result);

4-2. staticメソッドのサンプルコード

文字列を加工するstaticメソッドの例を見てみましょう。

C#
class StringHelper
{
public static string ToUpperText(string text)
{
return text.ToUpper();
}
}

使い方は次のとおりです。

C#
string result = StringHelper.ToUpperText("hello");
Console.WriteLine(result);

実行結果は次のようになります。

HELLO

このメソッドは、渡された文字列だけを使って処理をしています。特定のインスタンスの状態を必要としないため、staticメソッドとして自然です。

4-3. staticメソッドからインスタンスメンバーを直接呼べない理由

staticメソッドからインスタンスメンバーを直接呼ぶことはできません。

次のコードはエラーになります。

C#
class Person
{
public string Name = "田中";

public static void ShowName()
{
Console.WriteLine(Name);
}
}

Nameはインスタンスごとに異なる値を持つメンバーです。しかし、staticメソッドはインスタンスなしで呼び出されます。

C#
Person.ShowName();

このとき、C#は「どのPersonインスタンスのNameを表示すればよいのか」が分かりません。そのため、staticメソッドからインスタンスメンバーを直接使うことはできないのです。

使いたい場合は、インスタンスを作成してからアクセスします。

C#
class Person
{
public string Name = "田中";

public static void ShowName()
{
Person person = new Person();
Console.WriteLine(person.Name);
}
}

または、引数としてインスタンスを受け取る方法もあります。

C#
class Person
{
public string Name;

public static void ShowName(Person person)
{
Console.WriteLine(person.Name);
}
}

4-4. staticメソッドに向いている処理

staticメソッドに向いているのは、次のような処理です。

処理内容
計算処理税込み金額を計算する
文字列処理文字列を整形する
日付処理日付のフォーマットを変換する
入力値の検証メールアドレス形式をチェックする
共通ユーティリティよく使う処理をまとめる

たとえば、消費税込み金額を計算する処理はstaticメソッドにできます。

C#
class TaxCalculator
{
public static int AddTax(int price)
{
return (int)(price * 1.1);
}
}

呼び出しは次のようになります。

C#
int total = TaxCalculator.AddTax(1000);
Console.WriteLine(total);

4-5. staticメソッドを使いすぎると起きる問題

staticメソッドは便利ですが、使いすぎると次のような問題が起きやすくなります。

問題内容
状態管理が難しくなるstaticフィールドと組み合わせると値が共有され、予期しない変更が起きる
テストしにくくなる差し替えやモック化がしづらい
依存関係が見えにくくなるどこからでも呼べるため、コードの流れが追いづらくなる
オブジェクト指向の利点が薄れる継承やポリモーフィズムを活かしにくい

特に、staticフィールドに状態を持たせる場合は注意が必要です。複数の処理から同じ値を変更すると、バグの原因になることがあります。

5. staticフィールド・staticプロパティの使い方

staticフィールドやstaticプロパティは、クラス全体で共有する値を持ちたいときに使います。

5-1. staticフィールドとは

staticフィールドとは、クラスに属する変数のことです。

C#
class User
{
public static int Count = 0;
}

このCountは、Userクラス全体で1つだけ存在します。

C#
User.Count++;
User.Count++;

Console.WriteLine(User.Count);

実行結果は次のようになります。

2

staticフィールドは、インスタンスを作らなくても使えます。

5-2. staticプロパティとは

staticプロパティは、クラスに属するプロパティです。

C#
class Config
{
public static string SiteName { get; set; } = "My Site";
}

使い方は次のようになります。

C#
Console.WriteLine(Config.SiteName);

Config.SiteName = "New Site";
Console.WriteLine(Config.SiteName);

プロパティにすることで、値の取得や設定を制御しやすくなります。

C#
class Config
{
private static string siteName = "My Site";

public static string SiteName
{
get { return siteName; }
set
{
if (!string.IsNullOrEmpty(value))
{
siteName = value;
}
}
}
}

このように、staticプロパティを使えば、共通設定値を安全に扱いやすくなります。

5-3. 複数のインスタンスで値が共有される仕組み

staticフィールドは、複数のインスタンスを作っても共有されます。

C#
class Product
{
public static int TotalCount = 0;
public string Name;

public Product(string name)
{
Name = name;
TotalCount++;
}
}

次のように複数のインスタンスを作ります。

C#
Product p1 = new Product("りんご");
Product p2 = new Product("みかん");
Product p3 = new Product("バナナ");

Console.WriteLine(Product.TotalCount);

実行結果は次のようになります。

3

TotalCountは、各インスタンスごとではなくProductクラス全体で共有されています。そのため、作成された商品数をカウントできます。

5-4. カウンター機能を例にしたstaticフィールドのサンプル

staticフィールドを使ったカウンターの例を見てみましょう。

C#
class AccessCounter
{
public static int Count = 0;

public static void Add()
{
Count++;
}

public static void Show()
{
Console.WriteLine($"アクセス数: {Count}");
}
}

呼び出しは次のようになります。

C#
AccessCounter.Add();
AccessCounter.Add();
AccessCounter.Add();

AccessCounter.Show();

実行結果は次のようになります。

アクセス数: 3

このように、staticフィールドを使うと、クラス全体で共有するカウンターを作れます。

ただし、実際のアプリケーションで複数の処理が同時に値を更新する場合は、スレッドセーフ性にも注意が必要です。

5-5. staticな変数を使うときの注意点

staticな変数は便利ですが、次の点に注意しましょう。

注意点内容
値が共有されるどこかで変更すると他の場所にも影響する
初期化タイミングに注意期待したタイミングで初期化されないとバグになる
テストしにくくなる場合がある前のテストで変更した値が残ることがある
並行処理で問題が起きることがある複数スレッドから同時に変更すると不整合が起きる

特に、変更可能なstaticフィールドは扱いに注意が必要です。外部から自由に書き換えられるpublicなstaticフィールドは、できるだけ避けた方が安全です。

C#
public static int Count;

より安全にするなら、privateフィールドとpublicプロパティを組み合わせます。

C#
class Counter
{
private static int count;

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

public static void Add()
{
count++;
}
}

このようにすると、外部から勝手にCountを書き換えられなくなります。

6. staticクラスとは

C#では、クラス自体にstaticを付けることもできます。これをstaticクラスと呼びます。

staticクラスは、インスタンスを作らずに使うことを前提としたクラスです。

6-1. staticクラスの基本

staticクラスは次のように定義します。

C#
static class MathHelper
{
public static int Square(int x)
{
return x * x;
}
}

呼び出しは次のようになります。

C#
int result = MathHelper.Square(5);
Console.WriteLine(result);

実行結果は次のようになります。

25

staticクラスは、共通処理やユーティリティメソッドをまとめるときによく使われます。

6-2. staticクラスはインスタンス化できない

staticクラスはインスタンス化できません。

次のコードはエラーになります。

C#
MathHelper helper = new MathHelper();

staticクラスは、クラス名から直接使うためのクラスです。そのため、newでオブジェクトを作ることはできません。

C#
MathHelper.Square(10);

このように使うのが正しい方法です。

6-3. staticクラスに定義できるメンバー

staticクラスには、staticメンバーだけを定義できます。

C#
static class AppUtility
{
public static string AppName = "Sample App";

public static void ShowAppName()
{
Console.WriteLine(AppName);
}
}

次のようなインスタンスメンバーは定義できません。

C#
static class AppUtility
{
public string Name;
}

staticクラスはインスタンス化できないため、インスタンスメンバーを持つ意味がありません。そのため、C#ではstaticクラス内のメンバーもstaticである必要があります。

6-4. ユーティリティクラスでstaticクラスを使う例

staticクラスは、共通処理をまとめるユーティリティクラスに向いています。

C#
static class TextUtility
{
public static bool IsEmpty(string text)
{
return string.IsNullOrEmpty(text);
}

public static string TrimText(string text)
{
return text.Trim();
}
}

使い方は次のとおりです。

C#
string name = "  Tanaka  ";

if (!TextUtility.IsEmpty(name))
{
Console.WriteLine(TextUtility.TrimText(name));
}

このように、特定のオブジェクト状態を持たず、入力値だけで結果が決まる処理はstaticクラスにまとめやすいです。

6-5. staticクラスと通常クラスの使い分け

staticクラスと通常クラスは、用途によって使い分けます。

種類向いている用途
staticクラス共通処理、ユーティリティ、定数管理
通常クラス状態を持つオブジェクト、業務データ、振る舞いを持つモデル

たとえば、計算処理だけをまとめるならstaticクラスで問題ありません。

C#
static class PriceHelper
{
public static int AddTax(int price)
{
return (int)(price * 1.1);
}
}

一方、ユーザーごとに名前や年齢などの状態を持つ場合は、通常クラスにします。

C#
class User
{
public string Name { get; set; }
public int Age { get; set; }
}

「そのクラスから複数のオブジェクトを作りたいか」を考えると、使い分けしやすくなります。

7. staticコンストラクターとは

C#には、staticメンバーを初期化するためのstaticコンストラクターがあります。

通常のコンストラクターはインスタンスを作るときに実行されますが、staticコンストラクターはクラスに対して一度だけ実行されます。

7-1. staticコンストラクターの役割

staticコンストラクターは、staticフィールドやstaticプロパティを初期化するために使います。

C#
class AppConfig
{
public static string AppName;

static AppConfig()
{
AppName = "Sample Application";
}
}

このように、static クラス名()の形で定義します。

staticコンストラクターにはアクセス修飾子を付けません。また、引数も指定できません。

C#
static AppConfig()
{
AppName = "Sample Application";
}

7-2. staticコンストラクターが実行されるタイミング

staticコンストラクターは、そのクラスが初めて使われる前に自動的に実行されます。

C#
class Sample
{
public static string Message;

static Sample()
{
Console.WriteLine("staticコンストラクターが実行されました");
Message = "こんにちは";
}
}

次のコードを実行します。

C#
Console.WriteLine(Sample.Message);

実行結果は次のようになります。

staticコンストラクターが実行されました
こんにちは

Sample.Messageを使う前に、staticコンストラクターが自動的に実行されています。

7-3. staticフィールドの初期化に使う方法

staticコンストラクターは、単純な初期値だけでなく、少し複雑な初期化処理にも使えます。

C#
class Settings
{
public static DateTime StartTime;

static Settings()
{
StartTime = DateTime.Now;
}
}

使い方は次のとおりです。

C#
Console.WriteLine(Settings.StartTime);

この例では、Settingsクラスが初めて使われるタイミングでStartTimeに現在時刻が設定されます。

7-4. 通常のコンストラクターとの違い

staticコンストラクターと通常のコンストラクターには、次のような違いがあります。

項目staticコンストラクター通常のコンストラクター
実行タイミングクラスが初めて使われる前インスタンス作成時
実行回数クラスごとに1回newするたびに実行
対象staticメンバーインスタンスメンバー
アクセス修飾子付けないpublicなどを付けられる
引数指定できない指定できる

通常のコンストラクターは、インスタンスごとの初期化に使います。

C#
class Person
{
public string Name;

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

staticコンストラクターは、クラス全体で共有されるstaticメンバーの初期化に使います。

7-5. staticコンストラクターの注意点

staticコンストラクターを使うときは、次の点に注意しましょう。

注意点内容
自分で直接呼び出せないC#が自動的に呼び出す
引数を指定できない初期化に外部値を渡す用途には向かない
例外に注意staticコンストラクターで例外が起きるとクラスが使えなくなる場合がある
重い処理は避ける初回アクセス時に処理が遅くなる可能性がある

staticコンストラクターには、必要最小限の初期化処理を書くのが基本です。

8. Mainメソッドがstaticである理由

C#の学習を始めると、最初に次のようなコードを見ることが多いでしょう。

C#
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}

ここで出てくるMainメソッドにもstaticが付いています。

8-1. C#のMainメソッドとは

Mainメソッドは、C#プログラムの開始地点です。アプリケーションが実行されると、最初にMainメソッドが呼び出されます。

C#
static void Main(string[] args)
{
Console.WriteLine("プログラム開始");
}

現在のC#ではトップレベルステートメントを使って、Mainメソッドを明示的に書かない形式もあります。

C#
Console.WriteLine("Hello, World!");

ただし内部的には、プログラムの開始地点が必要であることに変わりはありません。

8-2. プログラム開始時にインスタンスが存在しないためstaticが必要

Mainメソッドがstaticである理由は、プログラム開始時点ではまだインスタンスが存在しないからです。

もしMainメソッドがインスタンスメソッドだった場合、呼び出すためには先にProgramクラスのインスタンスを作る必要があります。

C#
Program program = new Program();
program.Main();

しかし、プログラム開始前にはそのインスタンスを作る処理自体がまだ実行されていません。そこで、インスタンスなしで呼び出せるstaticメソッドとしてMainが定義されています。

C#
static void Main()
{
Console.WriteLine("開始");
}

このように、Mainはプログラムの入口であるため、staticである必要があります。

8-3. Mainメソッドから他のメソッドを呼ぶときの注意点

Mainメソッドはstaticメソッドです。そのため、同じクラス内のインスタンスメソッドを直接呼ぶことはできません。

次のコードはエラーになります。

C#
class Program
{
static void Main()
{
ShowMessage();
}

void ShowMessage()
{
Console.WriteLine("こんにちは");
}
}

ShowMessage()はインスタンスメソッドですが、Mainはstaticメソッドです。staticメソッドからインスタンスメソッドを直接呼べないため、エラーになります。

解決方法は2つあります。

1つ目は、呼び出すメソッドにもstaticを付ける方法です。

C#
class Program
{
static void Main()
{
ShowMessage();
}

static void ShowMessage()
{
Console.WriteLine("こんにちは");
}
}

2つ目は、インスタンスを作ってから呼び出す方法です。

C#
class Program
{
static void Main()
{
Program program = new Program();
program.ShowMessage();
}

void ShowMessage()
{
Console.WriteLine("こんにちは");
}
}

8-4. 初心者がよく見る「staticが必要です」エラーの原因

初心者がよく見るエラーの原因は、staticメソッドからインスタンスメンバーを直接使おうとしていることです。

C#
class Program
{
string message = "こんにちは";

static void Main()
{
Console.WriteLine(message);
}
}

このコードでは、messageはインスタンスフィールドです。しかし、Mainメソッドはstaticなので、どのインスタンスのmessageを使えばよいのか分かりません。

解決するには、messageをstaticにするか、インスタンスを作成します。

C#
class Program
{
static string message = "こんにちは";

static void Main()
{
Console.WriteLine(message);
}
}

または次のようにします。

C#
class Program
{
string message = "こんにちは";

static void Main()
{
Program program = new Program();
Console.WriteLine(program.message);
}
}

9. staticでよくあるエラーと解決方法

staticを学ぶときには、いくつかの典型的なエラーに出会います。ここでは、初心者がつまずきやすいエラーと解決方法を紹介します。

9-1. 「オブジェクト参照が必要です」エラー

C#でよくあるのが、次のようなエラーです。

静的でないフィールド、メソッド、またはプロパティに対して、オブジェクト参照が必要です

これは、インスタンスメンバーをインスタンスなしで呼び出そうとしたときに発生します。

C#
class Person
{
public string Name = "田中";
}

class Program
{
static void Main()
{
Console.WriteLine(Person.Name);
}
}

Nameはstaticではないため、Person.Nameのようにクラス名から直接呼び出せません。

解決方法は、インスタンスを作ることです。

C#
Person person = new Person();
Console.WriteLine(person.Name);

または、クラス全体で共有したい値ならstaticを付けます。

C#
class Person
{
public static string Name = "田中";
}

9-2. staticメソッド内でインスタンス変数を使おうとした場合

次のコードはエラーになります。

C#
class Sample
{
int number = 10;

public static void Show()
{
Console.WriteLine(number);
}
}

numberはインスタンス変数です。staticメソッドのShow()から直接使うことはできません。

解決方法は、インスタンスを作ることです。

C#
class Sample
{
int number = 10;

public static void Show()
{
Sample sample = new Sample();
Console.WriteLine(sample.number);
}
}

または、numberをstaticにします。

C#
class Sample
{
static int number = 10;

public static void Show()
{
Console.WriteLine(number);
}
}

ただし、値をインスタンスごとに分けたい場合は、staticにしてはいけません。

9-3. staticクラスにインスタンスメンバーを定義した場合

staticクラスには、インスタンスメンバーを定義できません。

次のコードはエラーになります。

C#
static class Utility
{
public string Name;
}

staticクラスはインスタンス化できないため、インスタンスフィールドを持てません。

正しくは、メンバーにもstaticを付けます。

C#
static class Utility
{
public static string Name = "便利クラス";
}

または、インスタンスメンバーを持たせたい場合は、staticクラスではなく通常クラスにします。

C#
class Utility
{
public string Name;
}

9-4. newできないstaticクラスをインスタンス化しようとした場合

staticクラスはnewできません。

C#
static class Utility
{
public static void Show()
{
Console.WriteLine("Hello");
}
}

次のコードはエラーになります。

C#
Utility utility = new Utility();

staticクラスはクラス名から直接使います。

C#
Utility.Show();

staticクラスは「インスタンスを作らずに使うクラス」と覚えておきましょう。

9-5. エラーを防ぐための考え方

static関連のエラーを防ぐには、次の考え方が役立ちます。

確認ポイント判断方法
クラス名から呼びたいかstaticにする
オブジェクトごとに値を変えたいかインスタンスにする
staticメソッドから使いたいかstaticメンバーか、インスタンス経由で使う
newして使う必要があるか通常クラスにする
共通処理だけをまとめたいかstaticクラスを検討する

迷ったときは、「この値や処理は、個別のオブジェクトごとに違うべきか」を考えましょう。違うべきならインスタンス、全体で共通ならstaticが候補になります。

10. staticを使うべきケース・使わないほうがよいケース

staticは便利ですが、使いどころを間違えると保守しにくいコードになります。ここでは、staticを使うべきケースと使わないほうがよいケースを整理します。

10-1. staticを使うべきケース

staticを使うべきなのは、主に次のようなケースです。

ケース
インスタンス状態に依存しない処理数値計算、文字列変換
アプリ全体で共通する値アプリ名、バージョン
変更されない定数的な値最大件数、固定メッセージ
ユーティリティ処理入力チェック、フォーマット変換
プログラムの開始点Mainメソッド

たとえば、次のような計算処理はstaticに向いています。

C#
static class AreaCalculator
{
public static double CircleArea(double radius)
{
return radius * radius * Math.PI;
}
}

このメソッドは、渡された半径だけで結果が決まります。特定のインスタンス状態を必要としないため、staticにしても自然です。

10-2. staticを使わないほうがよいケース

次のようなケースでは、staticを使わないほうがよい場合があります。

ケース理由
ユーザーごとに異なる情報を持つstaticにすると全員で共有されてしまう
注文ごとに異なる状態を持つインスタンスごとに管理すべき
テストで差し替えたい処理staticはモック化しにくい
状態が頻繁に変わる処理予期しない共有が起きやすい
継承や多態性を活かしたい処理staticではオブジェクト指向の柔軟性が下がる

たとえば、ユーザー情報をstaticにするのは不適切です。

C#
class User
{
public static string Name;
}

この場合、すべてのユーザーでNameが共有されてしまいます。ユーザーごとに名前を持たせたいなら、インスタンスメンバーにします。

C#
class User
{
public string Name { get; set; }
}

10-3. 共通処理・定数・ユーティリティ処理での活用

staticは、共通処理や定数的な値の管理に向いています。

C#
static class Constants
{
public const int MaxLoginCount = 5;
public static readonly string AppName = "Sample App";
}

また、ユーティリティ処理にもよく使われます。

C#
static class ValidationHelper
{
public static bool IsValidAge(int age)
{
return age >= 0 && age <= 120;
}
}

使い方は次のとおりです。

C#
if (ValidationHelper.IsValidAge(25))
{
Console.WriteLine("有効な年齢です");
}

このような処理は、特定のオブジェクトに属する必要がないため、staticでまとめると分かりやすくなります。

10-4. 状態を持つ処理ではインスタンスを使うべき理由

状態を持つ処理では、インスタンスを使う方が安全です。

たとえば、銀行口座を表すクラスを考えます。

C#
class BankAccount
{
public int Balance { get; private set; }

public void Deposit(int amount)
{
Balance += amount;
}
}

この場合、口座ごとに残高が異なるため、Balanceはインスタンスプロパティにするべきです。

C#
BankAccount account1 = new BankAccount();
BankAccount account2 = new BankAccount();

account1.Deposit(1000);
account2.Deposit(5000);

Console.WriteLine(account1.Balance);
Console.WriteLine(account2.Balance);

もしBalanceをstaticにしてしまうと、すべての口座で残高が共有されてしまいます。

C#
class BankAccount
{
public static int Balance;
}

これは現実の銀行口座としては不自然です。個別の状態を持つものには、インスタンスを使いましょう。

10-5. テストや保守性を考えたstaticの使い方

staticを使うと、どこからでも簡単に呼び出せます。しかしその反面、依存関係が見えにくくなり、テストや保守が難しくなることがあります。

特に、staticフィールドに変更可能な状態を持たせる場合は注意が必要です。

C#
class GlobalState
{
public static int CurrentUserId;
}

このような値は、どこからでも変更できてしまいます。そのため、バグが起きたときに「どこで値が変わったのか」を追いにくくなります。

staticを使う場合は、次のような方針を意識すると安全です。

方針内容
状態を持たないstaticメソッドを中心に使う入力値だけで結果が決まる処理にする
publicなstaticフィールドを避ける外部から自由に変更されないようにする
変更される共有状態は慎重に扱うバグや競合の原因になりやすい
テストしやすさを考える差し替えが必要な処理はインスタンス化を検討する

staticは便利な道具ですが、使いすぎず、必要な場所に限定して使うことが大切です。

11. C#のstaticに関するよくある質問

最後に、C#のstaticについて初心者が疑問に感じやすい点をQ&A形式で解説します。

11-1. staticとconstの違いは?

staticconstはどちらも共通の値を扱う場面で見かけますが、意味は異なります。

staticは「クラスに属する」ことを表すキーワードです。一方、constは「コンパイル時に決まる定数」を表します。

C#
class Sample
{
public static int Count = 0;
public const double Pi = 3.14;
}

constは暗黙的にstaticのように扱われるため、クラス名から呼び出せます。

C#
Console.WriteLine(Sample.Pi);

ただし、constは後から値を変更できません。

C#
Sample.Count = 10;

これは可能ですが、次のような変更はできません。

C#
Sample.Pi = 3.14159;

constは固定値、staticはクラスに属するメンバーと覚えておきましょう。

11-2. staticとreadonlyの違いは?

readonlyは、代入できるタイミングを制限するキーワードです。フィールドにreadonlyを付けると、宣言時またはコンストラクター内でしか値を設定できません。

C#
class Sample
{
public readonly int Number;

public Sample(int number)
{
Number = number;
}
}

static readonlyと書くこともできます。

C#
class AppConfig
{
public static readonly string AppName = "Sample App";
}

static readonlyは、クラスに属する読み取り専用の値です。constと違い、実行時に値を設定できます。

C#
class AppConfig
{
public static readonly DateTime StartTime = DateTime.Now;
}

DateTime.Nowのように実行時に決まる値はconstにはできませんが、static readonlyなら使えます。

11-3. staticメソッドはいつ使えばいい?

staticメソッドは、インスタンスの状態に依存しない処理に使います。

たとえば、次のような処理です。

C#
static class NumberHelper
{
public static bool IsEven(int number)
{
return number % 2 == 0;
}
}

このメソッドは、引数numberだけで結果が決まります。特定のオブジェクト状態を必要としないため、staticメソッドに向いています。

一方、オブジェクトごとの値を使う処理はインスタンスメソッドにします。

C#
class Person
{
public string Name { get; set; }

public void SayHello()
{
Console.WriteLine($"こんにちは、{Name}です。");
}
}

SayHello()Nameというインスタンスの状態を使うため、staticには向きません。

11-4. static変数はグローバル変数と同じ?

static変数は、グローバル変数に似た使い方ができる場合がありますが、完全に同じではありません。

C#には、C言語のような純粋なグローバル変数はありません。staticフィールドは、必ずどこかのクラスに属します。

C#
class GlobalSettings
{
public static string AppMode = "Debug";
}

呼び出しは次のようになります。

C#
Console.WriteLine(GlobalSettings.AppMode);

どこからでもアクセスできるpublic staticフィールドは、グローバル変数のように使えてしまいます。しかし、どこからでも変更できる値はバグの原因になりやすいです。

そのため、変更可能なstatic変数を安易に公開するのは避けましょう。

C#
class GlobalSettings
{
public static string AppMode = "Debug";
}

より安全にするなら、読み取り専用にします。

C#
class GlobalSettings
{
public static readonly string AppMode = "Debug";
}

または、privateにしてメソッドやプロパティ経由で制御します。

11-5. staticを付ければ処理は速くなる?

staticを付けたからといって、必ず処理が速くなるわけではありません。

staticは、主に「クラスに属するか、インスタンスに属するか」を表すためのキーワードです。速度改善のために何でもstaticにするのは適切ではありません。

たしかに、staticメソッドはインスタンスを作らずに呼び出せます。しかし、パフォーマンス上の差よりも、設計上その処理がstaticに向いているかどうかの方が重要です。

たとえば、次のような処理はstaticで問題ありません。

C#
static int Add(int a, int b)
{
return a + b;
}

しかし、ユーザーごとの情報を扱う処理をstaticにするのは不自然です。

C#
class User
{
public static string Name;
}

staticを使うかどうかは、処理速度ではなく「クラス全体で共有すべきか」「インスタンスごとに分けるべきか」で判断しましょう。

まとめ

C#の静的とは、staticキーワードによって表される「クラスに属する」仕組みです。staticメンバーはインスタンスを作らなくても、クラス名から直接呼び出せます。

staticとインスタンスの大きな違いは、値や処理がどこに属するかです。staticはクラス全体で共有され、インスタンスメンバーはオブジェクトごとに個別に管理されます。

staticメソッドは、計算処理や文字列処理など、インスタンスの状態に依存しない処理に向いています。staticフィールドやstaticプロパティは、クラス全体で共有する値を管理するときに使えます。また、staticクラスはユーティリティ処理をまとめる場面で便利です。

一方で、staticを使いすぎると、状態管理が難しくなったり、テストしづらくなったりすることがあります。特に、変更可能なstaticフィールドを多用すると、どこで値が変わったのか分かりにくくなります。

C#でstaticを使うときは、「この処理や値はクラス全体で共有すべきか」「それともインスタンスごとに持つべきか」を考えることが大切です。共通処理や定数的な値にはstaticを使い、個別の状態を持つものにはインスタンスを使うようにしましょう。