web-dev-qa-db-ja.com

C#で静的クラスを使用する場合

ここに MSDNがいつ静的クラスを使うべきか の下で言わなければならないものがあります:

static class CompanyInfo
{
    public static string GetCompanyName() { return "CompanyName"; }
    public static string GetCompanyAddress() { return "CompanyAddress"; }
    //...
}

特定のオブジェクトに関連付けられていないメソッドの場合は、静的クラスを編成の単位として使用します。また、静的クラスを使用すると、そのメソッドを呼び出すためにオブジェクトを作成する必要がないため、実装が簡単かつ高速になります。 System名前空間のMathクラスのメソッドのように、クラス内のメソッドを意味のある方法で整理すると便利です。

私には、その例は静的クラスの非常に多くの可能な使用シナリオを網羅しているようには見えません。過去には、関連する関数のステートレスなスイートに静的クラスを使用しましたが、それはそれについてです。それでは、どのような状況下でクラスを静的に宣言すべき(そしてそうすべきでない)べきか?

568
pbh101

私は以前のスタックオーバーフローの答えで静的クラスの私の考えを書きました:単一メソッドを持つクラス - 最善のアプローチ?

私は以前は静的メソッドで埋められたユーティリティクラスを気に入っていました。彼らは、そうでなければ冗長性とメンテナンスの地獄を引き起こしてしまうはずだったヘルパーメソッドの素晴らしい統合を行いました。それらは非常に使いやすく、インスタンス化も廃棄もなし、ただ忘れないでください。私はこれがサービス指向アーキテクチャーを作成するための私の最初の無意味な試みであったと思います - 彼らの仕事をしただけで他には何もしないたくさんのステートレスサービス。しかし、システムが成長するにつれて、ドラゴンが登場しています。

多態性

たとえば、UtilityClass.SomeMethodというメソッドがあるとしましょう。突然、機能を少し変更する必要があります。ほとんどの機能は同じですが、それでもいくつかの部分を変更する必要があります。静的メソッドではなかった場合は、派生クラスを作成し、必要に応じてメソッドの内容を変更できます。静的なメソッドなので、できません。確かに、古いメソッドの前後に機能を追加するだけでよい場合は、新しいクラスを作成してその中に古いクラスを呼び出すことができます。

インターフェースの弱点

論理的な理由から、静的メソッドはインタフェースを通じて定義できません。そして私たちは静的メソッドをオーバーライドすることができないので、静的クラスはそれらをそれらのインターフェースによって受け渡しする必要があるときは役に立ちません。これにより、ストラテジーパターンの一部として静的クラスを使用できなくなります。 インタフェースの代わりにデリゲートを渡すことで、いくつかの問題を修正することができます

テスト

これは基本的に上記のインターフェースの問題と密接に関連しています。インプリメンテーションを交換する私達の能力は非常に限られているので、私達は生産コードをテストコードに取り替えるのも困難になるでしょう。繰り返しになりますが、実際のオブジェクトではなくラッパーを受け入れることができるように、コードの大部分を変更する必要があります。

ブロブを助長する

通常、静的メソッドは効用メソッドとして使用され、効用メソッドは異なる目的を持つため、コヒーレントではない機能で埋め尽くされた大規模なクラスになります。目的が明確に定義されているのであれば、クラスの5倍のほうがいいでしょう。

パラメータクリープ

まず第一に、そのかわいくて無邪気な静的メソッドは単一のパラメータを取ります。機能が増えるにつれて、新しいパラメータがいくつか追加されています。もうすぐオプションのパラメータが追加されるので、メソッドのオーバーロードを作成します(またはそれらをサポートする言語ではデフォルト値を追加します)。やがて、我々は10個のパラメータをとる方法を持っています。最初の3つだけが本当に必要で、パラメーター4〜7はオプションです。しかし、パラメータ6が指定されている場合は、7〜9も入力する必要があります。この静的メソッドが実行したことを行うための単一の目的でクラスを作成した場合は、必要なパラメータをコンストラクタ、およびプロパティを介してユーザーがオプションの値を設定できるようにしたり、同時に複数の相互に依存する値を設定したりできるメソッドです。また、メソッドがこの程度の複雑さになった場合は、いずれにせよ、独自のクラスに属している必要があります。

理由なくクラスのインスタンスを作成することを消費者に要求する

最も一般的な引数の1つは、次のとおりです。その後、インスタンスを使用しなくても、この単一メソッドを呼び出すためのインスタンスを作成することをクラスのコンシューマに要求するのはなぜですか。クラスのインスタンスを作成することは、ほとんどの言語で非常に安価な操作なので、速度は問題になりません。消費者に追加のコード行を追加することは、将来的により保守可能なソリューションの基礎を築くための低コストです。そして最後に、インスタンスの作成を避けたい場合は、簡単に再利用できるクラスのシングルトンラッパーを作成するだけです。ただし、これはあなたのクラスがステートレスであるという要件を作ります。ステートレスではない場合でも、長期的に見ればすべてのメリットを享受しながら、すべてを処理する静的ラッパーメソッドを作成できます。最後に、インスタンス化をシングルトンのように隠すクラスを作成することもできます。MyWrapper.Instanceは、new MyClass();を返すプロパティです。

絶対にシスを扱うのは1人だけです

もちろん、静的メソッドが私の嫌いなところには例外があります。肥大化する危険性がない真のユーティリティクラスは、静的メソッドの優れたケースです。例としてSystem.Convertがあります。あなたのプロジェクトが将来のメンテナンスを必要としない一回限りのものであるなら、全体的なアーキテクチャはそれほど重要ではありません - 静的でも非静的でも、開発速度は重要です。

規格、規格、規格!

インスタンスメソッドを使用しても、静的メソッドを使用することが妨げられることはありません。差別化の背後にある推論があり、それが標準化されている限り。さまざまな実装方法で広がるビジネスレイヤを見渡すことよりも悪いことはありません。

690

クラスを静的にするか非静的にするかを決めるときは、どのような情報を表現しようとしているのかを調べる必要があります。これはより ' ボトムアップ 'スタイルのプログラミングを必要とし、そこであなたが最初に表現しているデータに集中します。あなたが書いているクラスは、岩のような現実世界のオブジェクトですか、それとも椅子ですか。これらは物理的なもので、色、重量などの物理的な属性を持っているので、異なるプロパティを持つ複数のオブジェクトをインスタンス化することができます。黒い椅子と赤い椅子が同時に欲しいのですが。同時に2つの設定が必要な場合は、各オブジェクトを一意にして同時に存在させることができるように、それをオブジェクトとしてインスタンス化したいことがすぐにわかります。

反対に、静的関数は、実世界のオブジェクトや簡単に表現できるオブジェクトに属さないアクションに向いています。 C#の前身は、クラスには存在しないグローバル関数を定義できるC++とCです。これは ' top-down 'プログラミングに向いています。静的メソッドは、「オブジェクト」がタスクを実行しても意味がない場合に使用できます。クラスの使用を強制することで、関連機能をグループ化しやすくなり、より保守しやすいコードを作成できるようになります。

ほとんどのクラスは静的または非静的のどちらでも表すことができますが、疑問があるときはOOPルートに戻って自分が表しているものについて考えてみてください。これは、アクションを実行しているオブジェクト(スピードを上げたり、スピードを落としたり、方向転換したりすることができる車)なのか、それとももっと抽象的なもの(アウトプットを表示するようなもの)でしょうか。

内側のOOPに連絡を取ってください。

138
Despertar

C#3.0では、拡張メソッドはトップレベルの静的クラスにしか存在できません。

35
Mark Cidade

もしあなたがコード分析ツール(例えば FxCop )を使うなら、そのメソッドがインスタンスデータにアクセスしないならば、あなたはメソッドをstaticとマークすることをお勧めします。原理は、パフォーマンスが向上したことです。 MSDN:CA1822 - メンバーを静的としてマークする

それは、規則よりもガイドラインのようなものです、本当に...

22
user25306

工場では静的クラスを使う傾向があります。たとえば、これは私のプロジェクトの1つのロギングクラスです。

public static class Log
{
   private static readonly ILoggerFactory _loggerFactory =
      IoC.Resolve<ILoggerFactory>();

   public static ILogger For<T>(T instance)
   {
      return For(typeof(T));
   }

   public static ILogger For(Type type)
   {
      return _loggerFactory.GetLoggerFor(type);
   }
}

あなたは、IoCが静的アクセサを使って呼び出されることに気づいたかもしれません。 ほとんどの場合 クラスの静的メソッドを呼び出すことができるのであれば、これで十分です。わかりやすくするために、クラスを静的としてマークしています。

12
Rob

静的クラスはとても便利で場所があります。例えばライブラリです。

私が提供できる最良の例は、数学関数のライブラリを含むSystem名前空間の静的クラスである.Net Mathクラスです。

それは他のものと同じですが、その仕事に適したツールを使用してください。

空クラスを曖昧にして間違っていると却下してはいけません。それらを使用しないでください。

C#.Netには、Mathクラスと同じように使用される静的クラスがいくつか含まれています。

正しい実装を考えれば、それらは非常に便利です。

多数のビジネス関連のタイムゾーン関数を含む静的なTimeZoneクラスがあります。Mathクラスのように、グローバルにアクセス可能なTimeZone関連の関数(メソッド)が静的クラスに含まれているので、クラスのインスタンスを複数作成する必要はありません。 。

10
Don

私は再利用の単位として、クラスではなく関数を使いたいときに静的クラスを使い始めました。以前は、静的クラスの悪さについてはすべてでした。しかし、 F# を学ぶことで、新しい見方をすることができました。

これはどういう意味ですか?さて、いくつかのスーパー _ dry _ コードを作成するとき、私は結局1つのメソッドクラスの束になってしまうと言います。これらのメソッドを静的クラスに引き込んでから、デリゲートを使用してそれらを依存関係に注入するだけです。これはまた私の 依存性注入 (Autofacを選択した)(DI)コンテナでうまく機能します。

もちろん、静的メソッドへの直接的な依存関係を取ることは依然として 通常 evilです(悪くない使用法がいくつかあります)。

10
bentayloruk

与えられた型のオブジェクトが特定のコンテキストの下で使うことができる「追加機能」を定義するための手段として静的クラスを使います。通常、それらは効用クラスであることがわかります。

それ以外に、「特定のオブジェクトに関連付けられていないメソッドには、静的クラスを構成単位として使用する」と私は思います。意図した使い方をよく説明してください。

9
Trap

これはOOPが開始されたときからのもう一つの古くからの非常に熱い質問です。もちろん、静的クラスを使用する(または使用しない)理由はたくさんあり、それらのほとんどは多数の回答で取り上げられています。

このクラスがシステム内で一意であり、プログラム内でそのインスタンスを持つことが意味をなさない場合は、クラスを静的にします。しかし、私はこの使用法を大クラス用に予約しています。私はMSDNの例のようにそのような小さなクラスを "static"として宣言することは決してなく、確かに、他のクラスのメンバーになる予定のクラスは宣言しません。

また、static methods とstatic classes は考慮すべき2つの異なる点に注意してください。受け入れられた答えで述べられる主な不利な点は静的な メソッド のためです。 static classes は通常のクラスと同じ柔軟性(プロパティとパラメータが関係する場合)を提供し、それらで使用されるすべてのメソッドはクラスの存在の目的に関連するはずです。

私の考えでは、静的クラスの候補の良い例は "FileProcessing"クラスです。これには、複雑なFileProcessing操作を実行するためのプログラムのさまざまなオブジェクトに関連するすべてのメソッドとプロパティが含まれます。このクラスの複数のインスタンスを持つことに意味があることはほとんどなく、静的であることによってプログラム内のすべてのものがすぐに利用できるようになります。

7
ThunderGr

私はヘルパーメソッドには静的クラスのみを使用しますが、C#3.0の出現により、それらには拡張メソッドを使用したいと思います。

シングルトンの「デザインパターン」を使用することがほとんどないのと同じ理由で、静的クラスのメソッドを使用することはほとんどありません。

2
jonnii

_ msdn _ に基づく:

  1. 静的クラスのインスタンスは作成できません
  2. クラスが静的として宣言されている場合、メンバー変数はそのクラスに対して静的である必要があります。
  3. 封印[継承できない]
  4. インスタンスコンストラクタを含めることはできません
  5. メモリ管理

例:数学計算(数学値)は変更されません[定義された値のための標準計算]

1
Vicky