はじめに
C#で開発していると、こんな提案をよく目にします。
メンバー 'GetHoge' はインスタンス データにアクセスしないため、static にマークできます (CA1822)
開発中に頻繁に出てくるので、ふと疑問が湧きました。
「そもそも、staticにすべきなの? しなくてもいいの?」
なんとなく従うのもどうかと思い、この提案の意味と、staticにすべきかどうかの判断基準を調べてみました。
環境
- .NET 10.0
- C# 13.0
- Visual Studio 2026
CA1822とは何か
提案の内容
CA1822は、.NETのコード分析(Code Analysis)が出す提案の1つです。
- ルールID: CA1822
- カテゴリ: パフォーマンス
- 重大度: 提案(Suggestion)
「警告」ではなく「提案」です。ビルドエラーや警告にはならず、Visual Studioのエディタ上に薄い点(グレーの3つの点)として表示されます。「こうした方がいいかも」くらいのニュアンスです。
ざっくり言うと、「このメソッド、クラスのフィールドやプロパティを何も使ってないから、staticにできるよ」と教えてくれています。
どんなときに出るのか
具体的なコードで見てみます。
public class OrderService
{
private readonly ILogger _logger;
public OrderService(ILogger logger)
{
_logger = logger;
}
// ⚠️ CA1822が出る
public decimal CalculateTax(decimal price)
{
return price * 0.1m;
}
// CA1822は出ない
public void ProcessOrder(Order order)
{
_logger.LogInformation("Processing order...");
// ...
}
}
CalculateTaxは引数のpriceだけを使って計算しており、_loggerのようなインスタンスフィールドには一切触れていません。一方、ProcessOrderは_loggerを使っているので提案は出ません。
つまり、クラスが持っているデータ(フィールドやプロパティ)を使っていないメソッドに対してこの提案が出ます。
staticにすると何がうれしいのか
「このメソッドはクラスの状態と無関係」だとわかる
個人的には、これが一番のメリットだと感じました。
staticが付いているメソッドを見たら、「このメソッドはクラスのフィールドやプロパティに触らない、引数だけで完結する処理なんだな」とすぐわかります。逆にstaticが付いていなければ、「クラスの状態を何か使っているんだろう」と予測できます。
つまり、コードを読む人にとっての手がかりになります。
パフォーマンスは良くなるの?
CA1822は「パフォーマンス」カテゴリの提案なので、速くなるのかと思って調べました。
結論から言うと、普通のコードではほぼ変わりません。
理由を簡単に説明すると、インスタンスメソッドは呼び出し時に裏側で「自分自身のインスタンス(this)」を引数として受け取っています。そのインスタンスを使わないのに毎回受け渡しているのは無駄なので、staticにすればその分だけ効率が良くなる、というのがこの提案の根拠です。
ただ、この差は本当にわずかです。Microsoftのドキュメントでも「パフォーマンスにシビアなコードで測定可能な向上が得られる」という書き方をしており、普通のアプリケーションコードで体感できるレベルの差ではありません。
なので、パフォーマンス目的でstaticにするというより、「意図が明確になる」というメリットの方が実務では大きいと思いました。
staticにすべきでないケース
では、CA1822が出たら常にstaticにすべきかというと、そうでもありません。調べていくと、staticにしないほうがよい場面がいくつかありました。
1. テストでモックしたいメソッド
ユニットテストでモック(Mock)を使う場合、staticメソッドはモックが難しいです。
// staticだとモックが難しい
public static decimal CalculateTax(decimal price)
{
return price * 0.1m;
}
// インスタンスメソッドならインターフェース経由でモックできる
public decimal CalculateTax(decimal price)
{
return price * 0.1m;
}
たとえば、IOrderServiceをモックしてCalculateTaxの戻り値を差し替える、というテストを書きたい場合、メソッドがstaticだとそれができません。テスタビリティを重視するプロジェクトでは、publicメソッドを安易にstaticにしないほうがよい場面があります。
2. DI(依存性注入)で管理しているクラス
DIコンテナでライフサイクルを管理しているクラスのメソッドをstaticにすると、ちぐはぐになることがあります。
クラス自体は「DIで注入して使う」という設計なのに、メソッドだけstaticになっていると、「あれ、このメソッドだけ直接呼べるの?」と混乱の元になります。
3. 将来インスタンスメンバーを使う予定がある場合
今はフィールドを使っていなくても、近い将来の実装で使う予定があるなら、staticにしないほうが自然です。
public class NotificationService
{
private readonly IEmailSender _emailSender; // 今後使う予定
// 今はまだ_emailSenderを使っていない
// → CA1822が出るが、staticにしないほうがいいかもしれない
public string FormatMessage(string userName, string content)
{
return $"{userName}さん、{content}";
}
}
ただし、「将来使うかも」という推測だけでstaticにしないのは判断が難しいところです。YAGNI(You Aren't Gonna Need It=今必要ないものは作らない)の原則に従えば、今staticにしておいて必要になったら外す方が素直かもしれません。ここは状況次第です。
4. 既にリリース済みのpublicメソッド
外部に公開しているライブラリのpublicメソッドをstaticに変更すると、利用者側のコードが壊れる可能性があります(呼び出し方がinstance.Method()からClassName.Method()に変わるため)。
Microsoftのドキュメントでも、リリース済みコードについては提案を抑制して問題ないと書かれています。
提案を非表示にする方法
staticにすべきでないと判断した場合、提案を消す方法もいくつかあります。
特定のメソッドだけ非表示にする
#pragma warning disableで囲む方法です。
#pragma warning disable CA1822
public decimal CalculateTax(decimal price)
{
return price * 0.1m;
}
#pragma warning restore CA1822
SuppressMessage属性でも非表示にできます。
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static")]
public decimal CalculateTax(decimal price)
{
return price * 0.1m;
}
プロジェクト全体で非表示にする
.editorconfigに以下を追加すると、プロジェクト全体でCA1822を無効化できます。
[*.cs]
dotnet_diagnostic.CA1822.severity = none
publicメソッドだけ対象外にする
CA1822には「どの公開範囲のメンバーを対象にするか」を設定するオプションがあります。たとえば、privateとinternalだけを対象にしたい場合は以下のように設定します。
[*.cs]
dotnet_code_quality.CA1822.api_surface = private, internal
こうすると、publicメソッドには提案が出なくなります。publicメソッドはテスタビリティやAPI互換性の観点からstaticにしたくない場面が多いので、この設定は実用的だと思いました。
個人的な判断基準
調べた内容を踏まえて、自分なりの判断基準を整理しました。
staticにする場合
- ユーティリティ的なメソッド(純粋な計算、変換処理など)
- クラスの状態に依存しないことが明確で、今後も使う見込みがない
- クラス内部でしか使わないヘルパーメソッド
staticにしない場合
- テストでモック対象になりうるpublicメソッド
- DI管理されたクラスで、staticにすると設計意図がぶれる
- 近い将来インスタンスメンバーを使う実装予定がある
- 既にリリース済みで、シグネチャ変更が利用者のコードを壊すリスクがある
判断フロー
既にリリース済みのpublic API?
└─ YES → staticにしない(利用者のコードが壊れるリスク)
テストでモック対象になる?
└─ YES → staticにしない(テスタビリティ優先)
将来インスタンスメンバーを使う予定がある?
└─ YES → staticにしない
└─ NO → staticにする
まとめ
- CA1822は「クラスのデータを使っていないメソッドはstaticにできるよ」という提案(警告ではない)
- パフォーマンスへの影響は、普通のコードではほぼ体感できない
- 実質的なメリットは「このメソッドはクラスの状態と無関係」と読み手に伝わること
- ただし常にstaticにすればいいわけではない(テスタビリティ、DI、API互換性、将来の拡張を考慮)
-
.editorconfigのapi_surface設定で、publicメソッドだけ対象外にする運用もできる - 非表示にしたい場合は
#pragma warning disableやSuppressMessage属性で対応可能
調べる前は「staticにすべきなのか、しなくてもいいのか」がよくわかっていませんでしたが、結局のところ文脈次第で判断が変わるものだということがわかりました。「パフォーマンスが上がるからstaticにする」というよりは、コードの意図やテストのしやすさとのバランスで決めるのがよさそうです。
参考になったら いいね や ストック をお願いします!
同じような経験をされた方のコメントもお待ちしています。
参考
- CA1822: メンバーを static にマークする - .NET(Microsoft Learn)
- コード分析規則の構成 - .NET(Microsoft Learn)
- static (C# リファレンス) - Microsoft Learn
関連リンク
技術ブログでも学びや検証内容をまとめています。
アウトプットで手当がもらえる会社 ONE WEDGE
株式会社ONE WEDGE では一緒に働く仲間を募集中!
技術記事を書くと手当がもらえる「IT系記事寄稿特別手当」という制度があります。
興味があればぜひカジュアルに話しましょう!
👉 採用サイト