C#のstaticとは?クラス・メソッド・変数の使い方と注意点を初心者向けに解説

はじめに

C#を学び始めると、staticというキーワードをよく見かけます。

たとえば、C#のプログラムで最初に目にすることが多い次のコードにもstaticが使われています。

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

また、次のような書き方もよく登場します。

C#
Math.Max(10, 20);
Console.WriteLine("こんにちは");

これらは、インスタンスを作らずにクラス名から直接呼び出している例です。

C#のstaticは、クラス、メソッド、変数、プロパティなどに付けられる修飾子です。正しく使うと便利ですが、意味を曖昧にしたまま使うと「なぜ値が共有されるのか」「なぜメソッドから変数を呼べないのか」といったエラーや混乱につながります。

この記事では、C#のstaticについて、クラス・メソッド・変数の使い方と注意点を初心者向けに解説します。

1. C#のstaticとは?まず押さえたい基本の意味

1-1. staticは「インスタンスではなく型そのものに属する」ための修飾子

C#のstaticとは、メンバーを「インスタンスではなく型そのものに属するもの」として扱うための修飾子です。

通常、クラスを使うときはnewでオブジェクトを作成します。

C#
User user = new User();

このように作られたuserがインスタンスです。

一方、staticを付けたメンバーは、個別のインスタンスに属しません。クラスそのものに属します。

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

このCountは、Sampleクラスから作られた各オブジェクトが別々に持つ値ではありません。Sampleという型そのものが持つ共通の値です。

1-2. staticを付けたメンバーはクラス名から直接呼び出せる

staticを付けたメンバーは、インスタンスを作らずにクラス名から直接呼び出せます。

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

呼び出すときは次のように書きます。

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

実行結果は次のとおりです。

8

Calculator calculator = new Calculator();のようにインスタンスを作らなくても使えます。

このように、staticは「特定のオブジェクトに依存しない処理」を書くときによく使われます。

1-3. 通常のクラス・メソッド・変数との違い

通常のメンバーは、インスタンスごとに存在します。

C#
class User
{
public string Name;
}

次のように2つのインスタンスを作ると、それぞれが別々のNameを持ちます。

C#
User user1 = new User();
user1.Name = "田中";

User user2 = new User();
user2.Name = "佐藤";

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

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

田中
佐藤

一方、staticフィールドはインスタンス間で共有されます。

C#
class User
{
public static int Count;
}

User.Countは、すべてのUserに共通する値です。

通常のメンバーは「各オブジェクトが持つもの」、staticメンバーは「クラス全体で共有するもの」と考えると理解しやすくなります。

1-4. 初心者がstaticでつまずきやすいポイント

初心者がC#のstaticでつまずきやすいポイントは、主に次のようなものです。

C#
class Sample
{
public int Number = 10;

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

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

Numberはインスタンスメンバーですが、Showはstaticメソッドです。staticメソッドは特定のインスタンスに属していないため、どのインスタンスのNumberを使えばよいのか判断できません。

正しく書くには、インスタンスを作ってからアクセスします。

C#
class Sample
{
public int Number = 10;

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

または、Number自体をstaticにします。

C#
class Sample
{
public static int Number = 10;

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

このように、staticを理解するには「インスタンスに属するのか」「クラスそのものに属するのか」を意識することが大切です。

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

2-1. staticフィールド・変数の書き方

staticフィールドは、クラス内のフィールドにstaticを付けて定義します。

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

使うときは、クラス名を使ってアクセスします。

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

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

1

staticフィールドは、クラス全体で共有したい値に使われます。

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

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

C#
Console.WriteLine(AppSettings.AppName);

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

staticメソッドは、メソッド定義にstaticを付けます。

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

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

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

実行結果は次のとおりです。

25

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

たとえば、文字列の整形、数値計算、変換処理などです。

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

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

staticプロパティも、プロパティにstaticを付けて定義します。

C#
class SystemInfo
{
public static string Version { get; set; } = "1.0.0";
}

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

C#
Console.WriteLine(SystemInfo.Version);

SystemInfo.Version = "1.1.0";

Console.WriteLine(SystemInfo.Version);

実行結果は次のとおりです。

1.0.0
1.1.0

staticプロパティは、staticフィールドを直接公開するよりも安全に値を扱いたい場合に使われます。

たとえば、外部から値を変更させたくない場合は、setprivateにできます。

C#
class AppInfo
{
public static string Name { get; private set; } = "My App";
}

この場合、外部から読み取りはできますが、直接変更はできません。

C#
Console.WriteLine(AppInfo.Name);

2-4. staticクラスの書き方

staticクラスは、クラス定義にstaticを付けます。

C#
static class StringHelper
{
public static bool IsNullOrWhiteSpace(string text)
{
return string.IsNullOrWhiteSpace(text);
}
}

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

C#
// エラー
// StringHelper helper = new StringHelper();

staticクラスの中に定義できるメンバーは、基本的にstaticメンバーだけです。

C#
static class TaxCalculator
{
public static decimal Calculate(decimal price)
{
return price * 1.1m;
}
}

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

C#
decimal result = TaxCalculator.Calculate(1000);
Console.WriteLine(result);

実行結果は次のとおりです。

1100.0

2-5. public・privateなどアクセス修飾子との組み合わせ

staticは、publicprivateなどのアクセス修飾子と組み合わせて使えます。

C#
class Sample
{
public static int PublicValue = 10;

private static int PrivateValue = 20;

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

public staticは、クラスの外からアクセスできます。

C#
Console.WriteLine(Sample.PublicValue);

一方、private staticはクラスの外からアクセスできません。

C#
// エラー
// Console.WriteLine(Sample.PrivateValue);

private staticは、クラス内部だけで使う共通値や補助メソッドに使われます。

C#
class PriceCalculator
{
private static decimal TaxRate = 0.1m;

public static decimal AddTax(decimal price)
{
return price + price * TaxRate;
}
}

3. static変数・staticフィールドの使い方

3-1. static変数はインスタンス間で共有される

static変数の大きな特徴は、インスタンス間で共有されることです。

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

public User()
{
Count++;
}
}

このクラスからインスタンスを作るたびに、Countが増えます。

C#
User user1 = new User();
User user2 = new User();
User user3 = new User();

Console.WriteLine(User.Count);

実行結果は次のとおりです。

3

Countは各インスタンスが別々に持っているのではなく、Userクラス全体で1つだけ存在します。

3-2. static変数とインスタンス変数の違い

static変数とインスタンス変数の違いをコードで確認してみましょう。

C#
class Player
{
public static int TotalCount = 0;
public int Level = 1;

public Player()
{
TotalCount++;
}
}

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

C#
Player player1 = new Player();
Player player2 = new Player();

player1.Level = 5;
player2.Level = 10;

Console.WriteLine(Player.TotalCount);
Console.WriteLine(player1.Level);
Console.WriteLine(player2.Level);

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

2
5
10

TotalCountはstaticなので、Playerクラス全体で共有されます。

一方、Levelはインスタンス変数なので、player1player2で別々の値を持ちます。

つまり、static変数は「全員で共有する値」、インスタンス変数は「それぞれが持つ値」です。

3-3. カウンターや共通設定値で使う例

static変数は、カウンターや共通設定値のように、クラス全体で共有したい値に使われます。

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

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

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

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

Console.WriteLine(AccessCounter.Count);

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

2

共通設定値の例も見てみましょう。

C#
class Config
{
public static string SiteName = "My Blog";
public static int PageSize = 20;
}

呼び出し側では、次のように使えます。

C#
Console.WriteLine(Config.SiteName);
Console.WriteLine(Config.PageSize);

ただし、変更可能なstatic変数はどこからでも値が変えられてしまう可能性があります。実務では、なるべくプロパティにしたり、readonlyを使ったりして安全に扱うことが多いです。

3-4. static変数の初期化タイミング

static変数は、型が初めて使われるタイミングで初期化されます。

C#
class Sample
{
public static int Number = GetNumber();

private static int GetNumber()
{
Console.WriteLine("初期化されました");
return 100;
}
}

次のように初めてSample.Numberにアクセスすると、static変数が初期化されます。

C#
Console.WriteLine(Sample.Number);
Console.WriteLine(Sample.Number);

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

初期化されました
100
100

初期化処理は毎回実行されるわけではありません。通常、型が初めて使われたときに一度だけ実行されます。

static変数の初期化処理が重い場合や、外部リソースに依存する場合は注意が必要です。

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

static変数は便利ですが、使い方を間違えるとバグの原因になります。

特に注意したいのは、値が共有されることです。

C#
class LoginUser
{
public static string Name;
}

このようなstatic変数にログインユーザー名を保存すると、複数のユーザーや複数の処理で同じ値を共有してしまう可能性があります。

C#
LoginUser.Name = "田中";
LoginUser.Name = "佐藤";

Console.WriteLine(LoginUser.Name);

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

佐藤

最初に入れた田中は上書きされます。

static変数は、すべての場所から同じ値を参照するため、意図しない変更が起きると原因を追いにくくなります。

変更可能なstatic変数を使うときは、次の点を意識しましょう。

  • 本当に全体で共有すべき値か

  • どこから変更される可能性があるか

  • マルチスレッド環境で問題が起きないか

  • テスト時に前回の値が残らないか

初心者のうちは、static変数を「便利な置き場所」として使いすぎないことが大切です。

4. staticメソッドの使い方

4-1. staticメソッドはインスタンス化せずに呼び出せる

staticメソッドは、インスタンスを作らずに呼び出せるメソッドです。

C#
class Greeting
{
public static void Hello()
{
Console.WriteLine("こんにちは");
}
}

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

C#
Greeting.Hello();

実行結果は次のとおりです。

こんにちは

通常のメソッドであれば、次のようにインスタンスを作る必要があります。

C#
class Greeting
{
public void Hello()
{
Console.WriteLine("こんにちは");
}
}

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

C#
Greeting greeting = new Greeting();
greeting.Hello();

staticメソッドは「そのクラスの機能として使いたいが、個別の状態は必要ない処理」に向いています。

4-2. ClassName.MethodName()で呼び出す方法

staticメソッドは、基本的に次の形式で呼び出します。

C#
クラス名.メソッド名();

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

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

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

C#
bool result = NumberHelper.IsEven(10);
Console.WriteLine(result);

実行結果は次のとおりです。

True

new NumberHelper()を作る必要はありません。

C#の標準ライブラリにも、staticメソッドは多く使われています。

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

Math.Maxは、数値の最大値を返すstaticメソッドです。

4-3. ユーティリティ処理でstaticメソッドを使う例

staticメソッドは、ユーティリティ処理でよく使われます。

ユーティリティ処理とは、特定のオブジェクトの状態に依存しない便利な処理のことです。

C#
class DateHelper
{
public static string FormatDate(DateTime date)
{
return date.ToString("yyyy年MM月dd日");
}
}

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

C#
DateTime today = new DateTime(2026, 6, 6);

string text = DateHelper.FormatDate(today);

Console.WriteLine(text);

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

2026年06月06日

文字列の加工にも使えます。

C#
class NameHelper
{
public static string CreateFullName(string lastName, string firstName)
{
return lastName + " " + firstName;
}
}

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

C#
string name = NameHelper.CreateFullName("山田", "太郎");
Console.WriteLine(name);
山田 太郎

このように、入力された値だけで結果が決まる処理はstaticメソッドに向いています。

4-4. staticメソッドから通常の変数やメソッドにアクセスできない理由

staticメソッドから、通常のインスタンス変数やインスタンスメソッドには直接アクセスできません。

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

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

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

理由は、Nameがインスタンスごとの値だからです。

たとえば、次のように複数のインスタンスがある場合を考えます。

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

Person person2 = new Person();
person2.Name = "佐藤";

staticメソッドは特定のインスタンスに属していないため、person1.Nameを使うべきか、person2.Nameを使うべきか判断できません。

そのため、インスタンスメンバーを使いたい場合は、インスタンスを明示します。

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

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

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

C#
Person person = new Person();
person.Name = "佐藤";

Person.ShowName(person);

または、メソッド自体をインスタンスメソッドにします。

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

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

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

C#
Person person = new Person();
person.ShowName();

4-5. static void Mainの意味

C#の入門でよく見るstatic void Mainにも、staticが使われています。

C#
static void Main(string[] args)
{
Console.WriteLine("Hello");
}

Mainメソッドは、プログラムの開始地点です。

プログラムを開始するために、先にクラスのインスタンスを作る必要があると困ります。そのため、Mainはインスタンス化しなくても呼び出せるstaticメソッドとして定義されます。

voidは戻り値がないことを表します。

つまり、static void Mainは次のような意味です。

  • static:インスタンスを作らずに呼び出せる

  • void:戻り値がない

  • Main:プログラムの開始地点となるメソッド

最近のC#では、トップレベルステートメントによりMainメソッドを明示しない書き方もできます。

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

ただし、内部的にはプログラムの開始地点が必要であり、static void Mainの考え方はC#の基本として理解しておくと役立ちます。

5. staticクラスの使い方

5-1. staticクラスはnewでインスタンス化できない

staticクラスは、newでインスタンス化できないクラスです。

C#
static class AppHelper
{
public static void ShowMessage()
{
Console.WriteLine("メッセージを表示します");
}
}

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

C#
AppHelper.ShowMessage();

一方、次のようにインスタンス化しようとするとエラーになります。

C#
// エラー
// AppHelper helper = new AppHelper();

staticクラスは、最初から「インスタンスを作らずに使うクラス」として設計されます。

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

staticクラスの中には、staticメンバーを定義します。

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

public static string AppName { get; set; } = "Sample";

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

staticクラスに、通常のインスタンスフィールドやインスタンスメソッドを定義することはできません。

C#
static class BadUtility
{
// エラー
// public int Number;

// エラー
// public void Show()
// {
// }
}

staticクラスはインスタンス化できないため、インスタンスメンバーを持つ意味がないからです。

5-3. ユーティリティクラスとして使う例

staticクラスは、ユーティリティクラスとしてよく使われます。

C#
static class StringUtil
{
public static string ToUpperText(string text)
{
if (string.IsNullOrEmpty(text))
{
return "";
}

return text.ToUpper();
}

public static int CountCharacters(string text)
{
if (text == null)
{
return 0;
}

return text.Length;
}
}

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

C#
Console.WriteLine(StringUtil.ToUpperText("hello"));
Console.WriteLine(StringUtil.CountCharacters("hello"));

実行結果は次のとおりです。

HELLO
5

このように、データを受け取り、加工して返すだけの処理はstaticクラスにまとめやすいです。

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

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

staticクラスに向いているのは、次のような処理です。

  • インスタンスごとの状態を持たない

  • 入力値だけで結果が決まる

  • 共通の便利機能として使いたい

  • Mathクラスのように機能をまとめたい

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

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

一方、通常クラスに向いているのは、インスタンスごとの状態を持つ場合です。

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

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

ユーザーごとにNameが違うため、通常クラスとして設計するのが自然です。

5-5. staticクラスを多用しすぎるデメリット

staticクラスは便利ですが、多用しすぎると設計が硬くなることがあります。

たとえば、どこからでも呼び出せるstaticメソッドに処理を集めすぎると、コードの依存関係が見えにくくなります。

C#
static class GlobalService
{
public static void Save()
{
// 保存処理
}

public static void SendMail()
{
// メール送信処理
}

public static void WriteLog()
{
// ログ出力処理
}
}

このように何でもstaticクラスに詰め込むと、後から変更しにくいコードになります。

また、テスト時に差し替えが難しいという問題もあります。たとえば、データベース接続や外部API通信のような処理をstaticメソッドにしてしまうと、テスト用の処理に置き換えにくくなります。

staticクラスは、状態を持たない単純なユーティリティ処理に使うのが基本です。

6. staticと似たキーワード・関連機能の違い

6-1. staticとconstの違い

staticconstは混同されやすいキーワードです。

constは、コンパイル時に値が決まる定数を定義するときに使います。

C#
class MathValues
{
public const double Pi = 3.14;
}

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

C#
Console.WriteLine(MathValues.Pi);

constで定義した値は変更できません。

C#
// エラー
// MathValues.Pi = 3.14159;

一方、staticは「型に属する」ことを表すキーワードです。

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

このCountは変更できます。

C#
Counter.Count++;

大きな違いは、constは定数、staticは型に属するメンバーを表す点です。

なお、constは暗黙的にstaticのようにクラス名からアクセスできますが、staticとは目的が異なります。

6-2. static readonlyとの違い

static readonlyは、staticフィールドを読み取り専用にする書き方です。

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

readonlyを付けたフィールドは、宣言時またはコンストラクターでしか値を設定できません。

staticフィールドの場合は、staticコンストラクターで値を設定できます。

C#
class AppConfig
{
public static readonly DateTime StartTime;

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

constとの違いは、実行時に値を決められる点です。

C#
class Sample
{
public const int MaxCount = 100;

public static readonly DateTime CreatedAt = DateTime.Now;
}

constはコンパイル時に決まる値に使います。

static readonlyは、実行時に決まるが、その後は変更したくない値に使います。

6-3. staticコンストラクターとは

staticコンストラクターは、staticメンバーの初期化に使う特別なコンストラクターです。

C#
class Settings
{
public static string AppName;

static Settings()
{
AppName = "My Application";
Console.WriteLine("staticコンストラクターが実行されました");
}
}

staticコンストラクターは、通常、型が初めて使われる前に一度だけ実行されます。

C#
Console.WriteLine(Settings.AppName);
Console.WriteLine(Settings.AppName);

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

staticコンストラクターが実行されました
My Application
My Application

staticコンストラクターは、引数を持てません。また、publicprivateなどのアクセス修飾子を付けません。

C#
class Sample
{
static Sample()
{
// 初期化処理
}
}

staticフィールドの初期化処理が複雑な場合に使うと便利です。

6-4. using staticとは

using staticは、staticメンバーをクラス名なしで呼び出せるようにする機能です。

たとえば、通常は次のように書きます。

C#
Console.WriteLine(Math.Sqrt(16));
Console.WriteLine(Math.Max(10, 20));

using staticを使うと、次のように書けます。

C#
using static System.Math;

Console.WriteLine(Sqrt(16));
Console.WriteLine(Max(10, 20));

実行結果は次のとおりです。

4
20

using staticはコードを短くできますが、多用すると「どのクラスのメソッドなのか」が分かりにくくなることがあります。

初心者のうちは、まずはMath.Sqrt()Math.Max()のようにクラス名付きで書く方が理解しやすいです。

6-5. Singletonパターンとの違い

staticと似た使い方に、Singletonパターンがあります。

Singletonパターンは、インスタンスを1つだけ作る設計パターンです。

C#
class AppManager
{
private static AppManager _instance = new AppManager();

public static AppManager Instance
{
get { return _instance; }
}

private AppManager()
{
}

public void Run()
{
Console.WriteLine("実行します");
}
}

使うときは次のように書きます。

C#
AppManager.Instance.Run();

staticクラスとの違いは、Singletonは「インスタンスが存在する」点です。

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

C#
static class AppUtility
{
public static void Run()
{
Console.WriteLine("実行します");
}
}

Singletonは、1つだけのオブジェクトとして状態や振る舞いを管理したい場合に使われます。

ただし、Singletonもstaticと同じく、使いすぎると依存関係が見えにくくなったり、テストしにくくなったりします。

7. C#のstaticでよくあるエラーと対処法

7-1. 「オブジェクト参照が必要です」が出る原因

C#でstaticを学んでいると、次のようなエラーに出会うことがあります。

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

これは、staticメソッドなどからインスタンスメンバーに直接アクセスしようとしたときによく発生します。

C#
class Sample
{
public int Number = 10;

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

Numberはインスタンスメンバーです。つまり、new Sample()で作られたオブジェクトに属します。

しかし、Showはstaticメソッドなので、特定のオブジェクトに属していません。

対処法は、インスタンスを作ってアクセスすることです。

C#
class Sample
{
public int Number = 10;

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

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

C#
class Sample
{
public static int Number = 10;

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

ただし、何でもstaticにすればよいわけではありません。その値が本当にクラス全体で共有されてよいのかを考える必要があります。

7-2. staticメソッド内でインスタンスメンバーを使えない場合

次のコードもよくあるエラーです。

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

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

public static void Print()
{
ShowName();
}
}

ShowNameはインスタンスメソッドです。staticメソッドPrintから直接呼び出すことはできません。

対処法は、インスタンスを使って呼び出すことです。

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

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

public static void Print(User user)
{
user.ShowName();
}
}

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

C#
User user = new User();
user.Name = "田中";

User.Print(user);

または、Printをインスタンスメソッドにする方法もあります。

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

public void Print()
{
Console.WriteLine(Name);
}
}

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

C#
User user = new User();
user.Name = "田中";
user.Print();

インスタンスの状態を使う処理は、基本的にインスタンスメソッドにするのが自然です。

7-3. staticクラスをnewしようとしてエラーになる場合

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

C#
static class Logger
{
public static void Write(string message)
{
Console.WriteLine(message);
}
}

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

C#
// エラー
// Logger logger = new Logger();

正しくは、クラス名から直接呼び出します。

C#
Logger.Write("ログを出力します");

staticクラスは「newせずに使うクラス」です。

もしインスタンスごとの状態を持たせたい場合は、staticクラスではなく通常のクラスにします。

C#
class Logger
{
private string _prefix;

public Logger(string prefix)
{
_prefix = prefix;
}

public void Write(string message)
{
Console.WriteLine(_prefix + message);
}
}

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

C#
Logger logger = new Logger("[INFO] ");
logger.Write("起動しました");

7-4. static変数の値が意図せず共有される場合

static変数はインスタンス間で共有されます。

そのため、インスタンスごとに別々の値を持たせたい場合にstaticを付けると、意図しない動作になります。

C#
class User
{
public static string Name;
}

次のように使うと、値が上書きされます。

C#
User.Name = "田中";
User.Name = "佐藤";

Console.WriteLine(User.Name);

実行結果は次のとおりです。

佐藤

ユーザーごとに名前を持たせたいなら、staticを外します。

C#
class User
{
public string Name;
}

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

C#
User user1 = new User();
user1.Name = "田中";

User user2 = new User();
user2.Name = "佐藤";

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

実行結果は次のとおりです。

田中
佐藤

インスタンスごとに違う値にしたいなら、staticを付けてはいけません。

7-5. エラーを避けるための確認ポイント

C#のstatic関連エラーを避けるには、次の点を確認しましょう。

  • その値は全インスタンスで共有してよいか

  • そのメソッドはインスタンスの状態を使うか

  • staticメソッド内でインスタンスメンバーを直接使っていないか

  • staticクラスをnewしようとしていないか

  • static変数を一時的なデータ置き場にしていないか

特に重要なのは、「インスタンスごとの値」と「クラス全体の値」を区別することです。

たとえば、ユーザー名、商品名、残高、HP、レベルなどは、多くの場合インスタンスごとの値です。

C#
class Player
{
public string Name;
public int Hp;
}

一方、作成されたインスタンス数やアプリ共通の設定値などは、staticが使える場合があります。

C#
class Player
{
public static int TotalCount;
}

staticを付ける前に、「これは全員で1つの値でよいか」と考える習慣を付けましょう。

8. staticを使うべき場面・使わない方がよい場面

8-1. staticを使うべき代表的なケース

staticを使うべき代表的なケースは、インスタンスの状態に依存しない処理です。

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

  • 数値計算

  • 文字列の変換

  • 日付の整形

  • 共通定数や読み取り専用の設定値

  • インスタンス数のカウント

  • 汎用的なヘルパーメソッド

数値計算の例です。

C#
static class MathUtil
{
public static int Double(int value)
{
return value * 2;
}
}

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

C#
Console.WriteLine(MathUtil.Double(10));

実行結果は次のとおりです。

20

この処理は、特定のインスタンス状態を必要としません。引数だけで結果が決まるため、staticメソッドに向いています。

8-2. staticを避けた方がよいケース

staticを避けた方がよいのは、インスタンスごとに違う状態を持つ場合です。

たとえば、ユーザー情報をstaticにするのは適していません。

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

このようにすると、すべてのユーザーで同じNameAgeを共有してしまいます。

正しくは、インスタンスメンバーにします。

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

また、外部サービスへの接続、ファイル操作、データベース操作なども、安易にstaticにしない方がよい場合があります。

理由は、後から差し替えたり、テストしたりしにくくなるからです。

8-3. テストしにくくなる問題

staticメソッドやstatic変数は、テストしにくくなることがあります。

たとえば、次のようなコードを考えます。

C#
static class TimeProvider
{
public static DateTime Now()
{
return DateTime.Now;
}
}

このメソッドを使う処理は、実行する時刻によって結果が変わります。

C#
class MessageService
{
public string CreateMessage()
{
if (TimeProvider.Now().Hour < 12)
{
return "おはようございます";
}

return "こんにちは";
}
}

このようなコードは、テスト時に「現在時刻」を自由に変えにくいです。

実務では、インターフェースや依存性注入を使って差し替え可能にすることがあります。

初心者の段階では、まず「staticは差し替えにくい場合がある」と覚えておくとよいでしょう。

8-4. 状態を持つstaticはバグの原因になりやすい

staticメソッド自体は便利ですが、変更可能なstatic変数を持つと注意が必要です。

C#
class GameState
{
public static int Score;
}

どこからでも次のように変更できます。

C#
GameState.Score = 100;
GameState.Score = 200;
GameState.Score = 0;

プログラムが大きくなると、どこで値が変わったのか追いにくくなります。

特に、複数の処理が同時に動く環境では、static変数の変更が思わぬバグにつながることがあります。

staticで状態を持つ場合は、できるだけ変更箇所を限定しましょう。

C#
class GameState
{
public static int Score { get; private set; }

public static void AddScore(int point)
{
Score += point;
}

public static void Reset()
{
Score = 0;
}
}

このように、外部から直接値を変更させず、メソッド経由で操作する方が安全です。

8-5. 初心者向けの判断基準

初心者がstaticを使うか迷ったときは、次の基準で考えると分かりやすいです。

まず、インスタンスごとに値が変わるものにはstaticを付けません。

C#
class Product
{
public string Name;
public int Price;
}

商品ごとに名前や価格が違うため、staticにはしません。

次に、引数だけで結果が決まる処理はstaticに向いています。

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

また、アプリ全体で本当に1つだけ共有したい値はstaticにできます。

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

迷ったときは、「この値や処理は、特定のオブジェクトに関係するか」を考えましょう。

関係するならインスタンスメンバー、関係しないならstatic候補です。

9. C#のstaticをサンプルコードで理解する

9-1. static変数を使ったサンプル

static変数を使って、作成されたインスタンス数を数えるサンプルです。

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

public string Name;

public Member(string name)
{
Name = name;
Count++;
}
}

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

C#
Member member1 = new Member("田中");
Member member2 = new Member("佐藤");
Member member3 = new Member("鈴木");

Console.WriteLine(Member.Count);

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

3

Countはstatic変数なので、すべてのMemberインスタンスで共有されます。

一方、Nameはインスタンス変数なので、各メンバーごとに異なる値を持ちます。

C#
Console.WriteLine(member1.Name);
Console.WriteLine(member2.Name);
Console.WriteLine(member3.Name);

実行結果は次のとおりです。

田中
佐藤
鈴木

9-2. staticメソッドを使ったサンプル

staticメソッドを使って、税込価格を計算するサンプルです。

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

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

C#
int price = TaxHelper.AddTax(1000);

Console.WriteLine(price);

実行結果は次のとおりです。

1100

この処理は、インスタンスごとの状態を必要としません。価格を渡すと税込価格が返るだけなので、staticメソッドに向いています。

別の例として、文字列が空かどうかを調べるメソッドも作れます。

C#
class TextHelper
{
public static bool IsBlank(string text)
{
return string.IsNullOrWhiteSpace(text);
}
}

呼び出しは次のとおりです。

C#
Console.WriteLine(TextHelper.IsBlank(""));
Console.WriteLine(TextHelper.IsBlank("Hello"));

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

True
False

9-3. staticクラスを使ったサンプル

staticクラスを使って、計算用のユーティリティクラスを作ってみます。

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

public static int Subtract(int a, int b)
{
return a - b;
}

public static int Multiply(int a, int b)
{
return a * b;
}
}

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

C#
Console.WriteLine(Calculator.Add(10, 5));
Console.WriteLine(Calculator.Subtract(10, 5));
Console.WriteLine(Calculator.Multiply(10, 5));

実行結果は次のとおりです。

15
5
50

Calculatorは状態を持たず、計算処理だけを提供しています。このような場合はstaticクラスに向いています。

9-4. staticあり・なしの動作比較

staticありとstaticなしの違いを比較してみましょう。

まずはstaticなしの例です。

C#
class Counter
{
public int Count = 0;

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

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

C#
Counter counter1 = new Counter();
Counter counter2 = new Counter();

counter1.Add();
counter1.Add();

counter2.Add();

Console.WriteLine(counter1.Count);
Console.WriteLine(counter2.Count);

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

2
1

counter1counter2は別々のCountを持っています。

次に、staticありの例です。

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

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

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

C#
SharedCounter counter1 = new SharedCounter();
SharedCounter counter2 = new SharedCounter();

counter1.Add();
counter1.Add();

counter2.Add();

Console.WriteLine(SharedCounter.Count);

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

3

Countはstaticなので、counter1counter2で共有されます。

この違いは、C# staticを理解するうえで非常に重要です。

9-5. 実行結果からstaticの挙動を確認する

最後に、static変数とインスタンス変数の違いをまとめて確認できるコードを見てみましょう。

C#
class Sample
{
public static int StaticCount = 0;
public int InstanceCount = 0;

public void Add()
{
StaticCount++;
InstanceCount++;
}
}

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

C#
Sample sample1 = new Sample();
Sample sample2 = new Sample();

sample1.Add();
sample1.Add();
sample2.Add();

Console.WriteLine("StaticCount: " + Sample.StaticCount);
Console.WriteLine("sample1.InstanceCount: " + sample1.InstanceCount);
Console.WriteLine("sample2.InstanceCount: " + sample2.InstanceCount);

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

StaticCount: 3
sample1.InstanceCount: 2
sample2.InstanceCount: 1

StaticCountは共有されるため、合計で3になります。

InstanceCountは各インスタンスが別々に持つため、sample1は2、sample2は1になります。

この結果から、staticは「クラス全体で1つ」、インスタンスメンバーは「オブジェクトごとに1つ」と理解できます。

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

10-1. staticはメモリにずっと残るのか

staticメンバーは、通常のインスタンスメンバーとはライフサイクルが異なります。

インスタンスメンバーは、オブジェクトが作られ、そのオブジェクトが不要になるとガベージコレクションの対象になります。

一方、staticメンバーは型に属するため、基本的にはアプリケーションの実行中、長く保持されます。

C#
class Cache
{
public static string Data;
}

このようなstaticフィールドに大きなデータを入れたままにすると、メモリ使用量が増える原因になります。

ただし、細かな挙動は実行環境や型の読み込み方法にも関係します。初心者の段階では、「staticな値は長く残りやすいので、大きなデータや不要なデータを置きっぱなしにしない」と覚えておくとよいでしょう。

10-2. staticメソッドはどんなときに使うべきか

staticメソッドは、インスタンスの状態を使わない処理に使うべきです。

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

C#
class NumberUtil
{
public static bool IsPositive(int number)
{
return number > 0;
}
}

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

逆に、インスタンスのフィールドやプロパティを使う処理は、インスタンスメソッドにするのが自然です。

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

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

ShowNameは、そのユーザーのNameを使うため、staticではなくインスタンスメソッドにします。

10-3. static変数はグローバル変数と同じなのか

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

C#には、C言語のような意味でのグローバル変数は基本的にありません。変数はクラスやメソッドなど、何らかの型やスコープに属します。

C#
class GlobalLike
{
public static int Value = 10;
}

このようにpublic staticにすると、どこからでも次のようにアクセスできます。

C#
Console.WriteLine(GlobalLike.Value);

そのため、グローバル変数のように使えてしまいます。

しかし、どこからでも変更できるstatic変数は、値の変更箇所が分かりにくくなります。

C#
GlobalLike.Value = 100;

便利だからといって、何でもpublic staticにするのは避けましょう。

10-4. staticクラスは継承できるのか

staticクラスは継承できません。

次のようなstaticクラスがあるとします。

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

このクラスを継承することはできません。

C#
// エラー
// class MyUtility : Utility
// {
// }

staticクラスはインスタンス化できず、継承の対象にもなりません。

また、staticクラス自体も他のクラスを継承できません。ただし、すべての型と同じく、基本的にはobjectに由来する型として扱われます。

継承やポリモーフィズムを使いたい場合は、staticクラスではなく通常のクラスやインターフェースを使います。

10-5. 初心者はstaticをどこまで理解すればよいか

初心者が最初に理解すべきstaticのポイントは、次の3つです。

まず、staticメンバーはクラス名から直接呼び出せます。

C#
Math.Max(10, 20);
Console.WriteLine("Hello");

次に、static変数はインスタンス間で共有されます。

C#
class Sample
{
public static int Count;
}

そして、staticメソッドからインスタンスメンバーには直接アクセスできません。

C#
class Sample
{
public int Number;

public static void Show()
{
// Console.WriteLine(Number); // エラー
}
}

最初から細かい仕様をすべて覚える必要はありません。

まずは、「staticはインスタンスではなくクラスそのものに属する」という基本を押さえましょう。

この考え方が分かれば、staticメソッド、static変数、staticクラスの違いも理解しやすくなります。

まとめ

C#のstaticは、クラス、メソッド、変数、プロパティなどに付けられる重要な修飾子です。

staticを付けたメンバーは、インスタンスではなく型そのものに属します。そのため、クラス名から直接呼び出せます。

C#
ClassName.MethodName();
ClassName.Value;

staticメソッドは、インスタンスを作らずに呼び出せるメソッドです。数値計算、文字列加工、日付整形など、インスタンスの状態に依存しない処理に向いています。

static変数は、インスタンス間で共有される変数です。作成数のカウントや共通設定値などに使えますが、値が共有されるため注意が必要です。

staticクラスは、newでインスタンス化できないクラスです。ユーティリティ処理をまとめるときによく使われます。

一方で、staticを使いすぎると、値の変更箇所が分かりにくくなったり、テストしにくくなったりします。特に、変更可能なstatic変数はバグの原因になりやすいため慎重に扱いましょう。

C# staticを理解するコツは、「インスタンスごとに持つものか」「クラス全体で共有するものか」を区別することです。

インスタンスごとに違う値を持たせたい場合はstaticを付けません。クラス全体で共通の処理や値として扱いたい場合にstaticを使います。

この基本を押さえておけば、C#のstaticメソッド、static変数、staticクラスを正しく使い分けられるようになります。