web-dev-qa-db-ja.com

メソッドは静的にできますが、そうすべきですか?

Resharperは、静的にすることができるasp.netページごとに複数の機能を指摘するのが好きです。それらを静的にすれば役立ちますか?それらを静的にし、ユーティリティクラスに移動する必要がありますか?

351
dlamblin

静的メソッドとインスタンスメソッド
10.2.5静的およびインスタンスメンバ C#言語仕様の違いが説明しています。一般に、静的メソッドはインスタンスメソッドに比べて非常に小さなパフォーマンス強化を提供できますが、やや極端な状況でのみです(詳細については この回答 を参照してください)。

FxCopまたはコード分析のルールCA1822の状態:

」[メンバーを静的としてマーク]の後、コンパイラはこれらのメンバーに非仮想呼び出しサイトを発行します。これにより、現在のオブジェクトポインターがnullでないことを保証する各呼び出しの実行時チェックが防止されます。パフォーマンスに敏感なコードの場合、測定可能なパフォーマンスの向上をもたらす可能性があります。場合によっては、現在のオブジェクトインスタンスへのアクセスに失敗すると、正確性の問題が表れます。」

ユーティリティクラス
デザインで意味をなさない限り、ユーティリティクラスに移動しないでください。 ToRadians(double degrees)メソッドが角度を表すクラスに関連するように、静的メソッドが特定のタイプに関連する場合、そのメソッドがそのタイプの静的メンバーとして存在することは理にかなっています(これは、デモンストレーションの目的)。

235
Jeff Yates

パフォーマンス、名前空間の汚染などはすべて私の見解では二次的なものです。論理的なものを自問してください。メソッドは型のインスタンスで論理的に動作していますか、それとも型自体に関連していますか?後者の場合は、静的メソッドにします。自分の制御下にないタイプに関連する場合にのみ、ユーティリティクラスに移動します。

インスタンスに対して論理的に動作するメソッドが存在する場合がありますが、インスタンスの状態は使用しませんyet。たとえば、ファイルシステムを構築していて、ディレクトリの概念は持っているが、まだ実装していない場合は、ファイルシステムオブジェクトの種類を返すプロパティを記述できます。 「ファイル」-しかし、それはインスタンスに論理的に関連しているので、インスタンスメソッドであるべきです。これは、メソッドを仮想化する場合にも重要です。特定の実装には状態は必要ありませんが、派生クラスには必要な場合があります。 (たとえば、コレクションに読み取り専用かどうかを尋ねる-そのコレクションの読み取り専用フォームをまだ実装していないかもしれませんが、それは明らかにタイプではなくコレクション自体のプロパティです。)

252
Jon Skeet

クラス内でメソッドをstaticとしてマークすると、インスタンスメンバを使用しないことが明らかになります。これは、コードをざっと調べるときに役立ちます。

概念的に同じように密接に関連付けられている別のクラスで共有する場合を除き、必ずしも別のクラスに移動する必要はありません。

54
Mark Cidade

これはあなたのケースでは発生していないと思いますが、多くの静的メソッドを使用することで苦労しなければならないコードで見た「悪臭」の1つです。

残念ながら、これらは特定のアプリケーション状態を想定した静的メソッドでした。 (確かに、アプリケーションごとに1人のユーザーしかいません!Userクラスが静的変数でそれを追跡しないのはなぜですか?)それらはグローバル変数にアクセスするための栄光ある方法でした。また、静的コンストラクター(!)もありましたが、これはほとんど常に悪い考えです。 (私はいくつかの合理的な例外があることを知っています)。

ただし、静的メソッドは、オブジェクトのインスタンスの状態に実際に依存しないドメインロジックを除外する場合に非常に役立ちます。コードをより読みやすくすることができます。

正しい場所に置いてください。静的メソッドは、他のオブジェクトの内部状態を侵入的に操作していますか?代わりに、それらの動作がそれらのクラスの1つに属するという良いケースを作成できますか?懸念事項を適切に分離していない場合、後で頭痛の種になる可能性があります。

21
JasonTrue

これは興味深い読み物です:

http://thecuttingledge.com/?p=57

ReSharperは、メソッドを静的にすることを実際に提案しているわけではありません。たとえば、そのシグネチャに現れるクラスの1つとは対照的に、なぜそのメソッドがそのクラスにあるのかを自問する必要があります。

しかし、これがresharper documentaionが言うことです: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static

9
pajics

@Jason Trueの answer に追加するだけで、メソッドに「静的」を追加してもメソッドが「純粋」であることを保証しないことに注意することが重要です。それが宣言されているクラスに関してはステートレスになりますが、状態(アプリケーション構成など)を持つ他の「静的」オブジェクトにアクセスする可能性があります。これは常に悪いことではないかもしれませんが、個人的には、静的メソッドを好む傾向があります。純粋なメソッドであれば、周囲の状態を心配することなく、それらについて個別にテストおよび推論できます。

8
Benjol

クラス内の複雑なロジックの場合、インスタンスインプットがメソッドシグネチャで明確に定義され、インスタンスの副作用が発生しない、孤立したロジックの作成に役立つプライベートスタティックメソッドが見つかりました。すべての出力は、戻り値またはout/refパラメーターを介する必要があります。複雑なロジックを副作用のないコードブロックに分解すると、コードの可読性と開発チームの自信が向上します。

一方、ユーティリティメソッドの急増によってクラスが汚染される可能性があります。通常どおり、論理コーディング、ドキュメント、およびチームコーディング規則の一貫した適用により、これを軽減できます。

6
G-Wiz

特定のシナリオで最も読みやすく直感的な操作を行う必要があります。

パフォーマンスの引数は、極端な状況を除いて良いものではありません。実際に起こっているのは、インスタンスメソッドの1つの追加パラメーター(this)がスタックにプッシュされることだけです。

6
Eric Schoonover

ReSharperはロジックをチェックしません。メソッドがインスタンスメンバーを使用するかどうかのみをチェックします。メソッドがプライベートで、インスタンスメソッド(1つだけかもしれません)によってのみ呼び出される場合、これはインスタンスメソッドを許可するサインです。

5
brgerner

メソッドを静的にすることは、最初にそのクラスのインスタンスを作成せずに、クラスの外部からメソッドを呼び出すことができることを意味します。これは、サードパーティベンダーオブジェクトまたはアドオンを使用する場合に役立ちます。 con.Writeline();を呼び出す前に、最初にConsoleオブジェクト「con」を作成する必要がある場合を想像してください。

3
Austin

関数が多数のページで共有されている場合は、それらを基本ページクラスに配置し、その機能を使用するすべてのasp.netページにその機能を継承させることもできます(また、関数も静的である可能性があります)。

3
Mun

名前空間の汚染を制御するのに役立ちます。

2
Josh

ちょうど私のtuppence:共有静的メソッドのすべてをユーティリティクラスに追加すると、追加することができます

using static className; 

usingステートメントに追加します。これにより、コードの入力が速くなり、読みやすくなります。たとえば、私が継承したコードには「グローバル変数」と呼ばれるものが多数あります。インスタンスクラスであるクラスでグローバル変数を作成するのではなく、それらをすべてグローバルクラスの静的プロパティとして設定します。面倒な場合、それは仕事をし、静的な名前空間が既に参照されているため、名前でプロパティを参照することができます。

これが良い習慣かどうかはわかりません。 C#4/5とリファクタリングするためのレガシーコードについて多くのことを学ぶ必要があるので、Roselynのヒントを参考にしようとしています。

ジョーイ

0
Joseph Morgan