654

When to Use Static Classesの下で MSDN が述べていることは次のとおりです。

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

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

私には、その例は、静的クラスの考えられる使用シナリオをあまりカバーしていないように思えます。以前は、関連する関数のステートレス スイートに静的クラスを使用していましたが、それだけです。では、どのような状況で、クラスを static と宣言する必要がある (およびすべきでない) のでしょうか?

4

11 に答える 11

763

以前のスタック オーバーフローの回答で、静的クラスに関する私の考えを書きました

私は静的メソッドで満たされたユーティリティ クラスが大好きでした。彼らはヘルパー メソッドを大幅に統合しました。そうでなければ冗長性とメンテナンス地獄を引き起こします。それらは非常に使いやすく、インスタンス化も廃棄も必要ありません。これは、サービス指向のアーキテクチャを作成する最初の無意識の試みだったと思います。多くのステートレス サービスは、ただ自分の仕事だけを行い、他には何もしませんでした。しかし、システムが成長するにつれて、ドラゴンがやってくる。

ポリモーフィズム

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

インターフェイスの問題

論理上の理由から、静的メソッドはインターフェイスを介して定義できません。また、静的メソッドをオーバーライドできないため、静的クラスをインターフェイスで渡す必要がある場合、静的クラスは役に立ちません。これにより、静的クラスを戦略パターンの一部として使用できなくなります。インターフェイスの代わりにデリゲートを渡すことで、いくつかの問題を修正する可能性があります。

テスト

これは基本的に、上記のインターフェースの問題と密接に関連しています。実装を交換する能力は非常に限られているため、製品コードをテスト コードに置き換えるのも困難です。繰り返しますが、それらをラップすることはできますが、実際のオブジェクトの代わりにラッパーを受け入れることができるようにするためだけに、コードの大部分を変更する必要があります。

ブロブを育てる

通常、静的メソッドはユーティリティ メソッドとして使用され、ユーティリティ メソッドは通常異なる目的を持つため、一貫性のない機能で満たされた大きなクラスになってしまいます。理想的には、各クラスはシステム内で 1 つの目的を持つ必要があります。目的が明確に定義されている限り、5 倍のクラスを使用したいと思います。

パラメータクリープ

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

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

最も一般的な議論の 1 つは、クラスの消費者がこの単一のメソッドを呼び出すためのインスタンスを作成することを要求するのに、後でインスタンスを使用しないのはなぜですか? クラスのインスタンスを作成することは、ほとんどの言語で非常に安価な操作であるため、速度は問題になりません。消費者に余分なコード行を追加することは、将来的にはるかに保守しやすいソリューションの基盤を築くための低コストです。最後に、インスタンスの作成を避けたい場合は、簡単に再利用できるクラスのシングルトン ラッパーを作成するだけです。ただし、これにより、クラスがステートレスであることが要件になります。ステートレスでない場合でも、すべてを処理する静的ラッパー メソッドを作成できますが、長期的にはすべての利点が得られます。ついに、new MyClass();

絶対的なものを扱うのはシスだけ

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

スタンダード、スタンダード、スタンダード!

インスタンス メソッドを使用しても、静的メソッドの使用が妨げられることはありません。その逆も同様です。差別化の背後に理由があり、それが標準化されている限り。さまざまな実装方法が無秩序に広がるビジネス層を見渡すことほど悪いことはありません。

于 2008-10-27T21:01:00.293 に答える
162

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

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

ほとんどのクラスは、静的または非静的のいずれかで表すことができますが、疑わしい場合は、OOP ルートに戻って、何を表しているかを考えてみてください。これは、アクションを実行しているオブジェクト (加速、減速、方向転換が可能な車) か、より抽象的なもの (出力の表示など) ですか。

あなたの内なる OOP と連絡を取ってください。

于 2012-02-01T02:50:11.207 に答える
37

C# 3.0 の場合、拡張メソッドは最上位の静的クラスにのみ存在できます。

于 2008-10-27T20:57:06.323 に答える
30

コード分​​析ツール ( FxCopstaticなど) を使用する場合、メソッドがインスタンス データにアクセスしない場合は、そのメソッドをマークすることをお勧めします。理由は、パフォーマンスが向上することです。MSDN: CA1822 - メンバーを static としてマークします

これはルールというよりはガイドラインのようなものです。

于 2008-10-27T21:39:12.730 に答える
13

私はファクトリに静的クラスを使用する傾向があります。たとえば、これは私のプロジェクトの 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 が静的アクセサーで呼び出されていることに気付いたかもしれません。 ほとんどの場合、クラスで静的メソッドを呼び出すことができれば、それだけで十分なので、明確にするためにクラスを静的としてマークします。

于 2008-10-27T21:11:55.670 に答える
12

静的クラスは非常に便利で、ライブラリなどの場所があります。

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

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

静的クラスを間違っている、使用しない、または「1 つしか存在しない」または何もないと言うことは、静的クラスを使用しすぎるのと同じくらい間違っています。

C#.Net には、Math クラスと同様に使用される多数の静的クラスが含まれています。

したがって、正しい実装があれば、それらは非常に便利です。

多数のビジネス関連のタイムゾーン関数を含む静的な TimeZone クラスがあります。Math クラスのようにクラスの複数のインスタンスを作成する必要はありません.

于 2013-01-04T23:47:16.640 に答える
10

再利用の単位として、クラスではなく関数を使用したい場合に、静的クラスの使用を開始しました。以前は、静的クラスの弊害についてばかり考えていました。しかし、 F#を学ぶことで、それらを新しい観点から見ることができました。

これはどういう意味ですか?たとえば、スーパーDRYコードを作成すると、1 つのメソッドのクラスがたくさんできてしまいます。これらのメソッドを静的クラスにプルしてから、デリゲートを使用して依存関係に注入するだけです。これは、選択した Autofac の依存性注入(DI) コンテナーでもうまく機能します。

もちろん、静的メソッドに直接依存することは、通常は依然として悪いことです (悪いことではない使用法もあります)。

于 2011-07-01T09:34:51.860 に答える
9

特定のタイプのオブジェクトが特定のコンテキストで使用できる「追加機能」を定義する手段として、静的クラスを使用します。通常、それらはユーティリティ クラスであることが判明します。

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

于 2008-10-27T21:05:24.577 に答える
3

私はヘルパー メソッドに静的クラスしか使用していませんが、C# 3.0 の出現により、これらの拡張メソッドを使用するようになりました。

シングルトンの「デザインパターン」をめったに使用しないのと同じ理由で、静的クラスメソッドをめったに使用しません。

于 2008-10-27T21:00:33.883 に答える