web-dev-qa-db-ja.com

静的である可能性があるC#メソッドは静的である必要がありますか?

canが静的であるC#メソッドは静的である必要がありますか?

今日私達はこれについて話し合っており、私は一種のフェンスの上にいます。数行をリファクタリングする長いメソッドがあるとします。新しいメソッドは、おそらく親メソッドからいくつかのローカル変数を取り、値を返します。これはcouldが静的であることを意味します。

問題は次のとおりですすべき静的ですか?これは、設計や選択によって静的ではなく、インスタンスの値を参照しないという性質上、単純です。

102

場合によります。静的メソッドには実際に2つのタイプがあります。

  1. それらはすることができるので静的であるメソッド
  2. 静的でなければならないメソッド

小規模から中規模のコードベースでは、2つの方法を同じように扱うことができます。

最初のカテゴリ(静的にすることができる)にあるメソッドがあり、クラスの状態にアクセスするためにそれを変更する必要がある場合、静的メソッドをインスタンスメソッドに変換できるかどうかを判断するのは比較的簡単です。

ただし、大規模なコードベースでは、膨大な数の呼び出しサイトによって、静的メソッドを非静的メソッドに変換するのにコストがかかりすぎるかどうかを検索する可能性があります。多くの場合、呼び出し回数が表示され、「わかりました。このメソッドは変更せず、代わりに必要なことを実行する新しいメソッドを作成する」と言います。

その結果、次のいずれかになります。

  1. 多くのコードの重複
  2. メソッド引数の数の急増

それらの両方が悪いです。

したがって、私のアドバイスは、LOCが200Kを超えるコードベースがある場合、静的でなければならないメソッドは静的でなければならないということです。

非静的から静的へのリファクタリングは比較的簡単です(キーワードを追加するだけ)。そのため、後で静的にすることができるようにしたい場合(インスタンス外の機能が必要な場合)、静的にすることができます。ただし、逆リファクタリング、つまり静的になることが可能なインスタンスメソッドに変換する方法は、はるかにコストがかかります。

大きなコードベースの場合、エラーは概念的な純粋さよりも、拡張の容易さの方が優れています。

したがって、大きなプロジェクトでは、必要な場合を除いて、物事を静的にしないでください。小さなプロジェクトの場合は、好きなことをしてください。

59

notpublicそのクラスの静的メンバーにします。その理由は、それをpublic staticにすることはクラスのタイプについて何かを言っているからです:「このタイプはこの動作を行う方法を知っている」だけでなく、「この動作を実行するのはこのタイプの責任です」。そして、オッズはより大きなタイプと実際の関係がなくなったという振る舞いです。

だからといって、それをまったく静的にしないわけではありません。これを自問してみてください。新しい方法は論理的に別の場所に属しているのでしょうか?それに対して「はい」と答えることができる場合、おそらくそれを静的にしたい(そしてそれも移動したい)でしょう。それが真実ではない場合でも、静的にすることができます。 publicとマークしないでください。

便宜上、少なくともinternalとマークすることができます。これにより、通常、より適切なタイプに簡単にアクセスできない場合にメソッドを移動する必要がなくなりますが、クラスのユーザーへのパブリックインターフェースの一部として表示されないように、必要な場所にアクセスできます。 。

43
Joel Coehoorn

必ずしも。

パブリックメソッドを静的から非静的に移動することは重大な変更であり、すべての呼び出し元またはコンシューマーを変更する必要があります。メソッドがインスタンスメソッドのように見えても、インスタンスメンバーを使用していない場合は、将来を保証する手段としてインスタンスメソッドにすることをお勧めします。

20
Michael

はい。 「静的である可能性がある」理由は、それが呼び出されたオブジェクトの状態に対して動作しないためです。したがって、これはインスタンスメソッドではなく、クラスメソッドです。インスタンスのデータにアクセスせずに、必要なことを実行できる場合は、静的である必要があります。

13
JP Alioto

はい、そうです。さまざまな カップリングのメトリック は、クラスが他のクラス、メソッドなどの他のものにどのように依存するかを測定します。メソッドを静的にすることは、sure静的メソッドはメンバーを参照しません。

12
Jabe

静的としてマークすると、少し読みやすくなると思います...次に来る人は、関数全体を読み取らなければインスタンス変数を参照しないことを知っています...

8
Jason Punyon

静的メソッドは非静的メソッドよりも高速であるため、可能であれば、静的メソッドである必要がありますそして、それらを非静的のままにする特別な理由はありません

6
agnieszka

個人的には、私は無国籍の大ファンです。あなたのメソッドはクラスの状態にアクセスする必要がありますか?答えが「いいえ」の場合(そしておそらく「いいえ」の場合、そうでない場合は、静的メソッドにすることを検討しないでしょう)、そうです。

州へのアクセスがないことは頭痛の種です。他のクラスで必要とされないプライベートメンバーを非表示にすることは良い考えであるのと同様に、それを必要としないメンバーから状態を非表示にすることは良い考えです。アクセスの減少は、バグの減少を意味します。また、静的メンバーをスレッドセーフに保つことがはるかに容易になるため、スレッド化が容易になります。ランタイムは静的メソッドのパラメーターとしてthisへの参照を渡す必要がないため、パフォーマンスに関する考慮事項もあります。

もちろん欠点は、以前の静的メソッドが何らかの理由で状態にアクセスする必要があることが判明した場合は、状態を変更する必要があることです。これがパブリックAPIの問題になる可能性があることを理解したので、これがパブリッククラスのパブリックメソッドである場合、おそらくこれの影響について少し考える必要があります。それでも、これが実際に問題を引き起こしたという現実の状況に直面したことはありませんが、たぶん私は幸運なだけかもしれません。

だから、ええ、是非ともやってみてください。

6
Tamas Czinege

実際、ここでカプセル化について言及している人はほとんどいないことに驚いています。インスタンスメソッドは、すべてのプライベート(インスタンス)フィールド、プロパティ、メソッドに自動的にアクセスできます。基本クラスから継承されたすべての保護されたものに加えて。

コードを作成するときは、できるだけ公開しないように、また、アクセスが最小限になるようにコードを記述する必要があります。

したがって、そうです。コードを高速にすることが重要です。これは、メソッドを静的にする場合に起こりますが、通常は、コードをできるだけバグを発生させないようにすることよりも重要です。これを実現する1つの方法は、コードが「プライベートなもの」にできるだけアクセスできないようにすることです。

OPは明らかにこのシナリオではうまくいかず、新しいバグを作成できないリファクタリングについて話しているので、これは一見関係ないと思われるかもしれませんが、このリファクタリングされたコードは将来維持し、コードをより大きな「攻撃」にする修正が必要ですプライベートインスタンスメンバーにアクセスできる場合、新しいバグに関しては「表面」。したがって、一般的に私はここでの結論は、静的ではないという他の理由がない限り、"yesほとんどのメソッドは静的である必要があります"であると思います。そして、これは単に「カプセル化とデータ非表示をより適切に使用し、「より安全な」コードを作成する」ためです...

5
Thomas Hansen

できるからといって静的なものを作るのは良い考えではありません。静的メソッドは、偶然ではなく、設計上静的でなければなりません。

マイケルが言ったように、これを後で変更すると、それを使用しているコードが壊れます。

そうは言っても、実際には設計上静的なクラスのプライベートユーティリティ関数を作成しているようです。

4
17 of 26

数行をリファクタリングすることができ、結果のメソッドが静的である可能性がある場合、そのメソッドから引き出した行が包含クラスに属していないことを示している可能性があります。自分のクラス。

4
Chris Shaffer

個人的には静的にするしかありません。この場合、Resharperは警告を発行し、PMには「Resharperからの警告なし」というルールがあります。

2
Prankster

別の理由で、できる限り何でも静的に変換します。

静的関数は、JITされると、「this」パラメーターなしで呼び出されます。つまり、たとえば、3つのパラメーターの非静的関数(メンバーメソッド)が4つのパラメーターでスタックにプッシュされます。

静的関数としてコンパイルされた同じ関数は、3つのパラメーターで呼び出されます。これにより、JITのレジスタが解放され、スタックスペースを節約できます...

1
damageboy

メソッドとクラスについて考える必要があります。

  • それらをどのように使用しますか?
  • あなたはあなたのコードの異なるレベルからそれらへの多くのアクセスが必要ですか?
  • これは、ほとんどすべての考えられるプロジェクトで使用できるメソッド/クラスですか?.

最後の2つが「はい」の場合、メソッド/クラスはおそらく静的でなければなりません。

最もよく使用される例は、おそらくMathクラスです。すべてのメジャーOO言語にはそれがあり、すべてのメソッドは静的です。インスタンスを作成せずにいつでもどこでもそれらを使用できるようにする必要があるためです。

もう1つの良い例は、C#の Reverse() メソッドです。
これはArrayクラスの静的メソッドです。配列の順序を逆にします。

コード:

public static void Reverse(Array array)

すべての配列はArrayクラスのインスタンスであるため、何も返されず、配列が逆になります。

1
KdgDev

新しいメソッドprivate staticにする限り、重大な変更ではありません。実際、FxCopにはこのガイダンスがルールの1つとして含まれています( http://msdn.Microsoft.com/en-us/library/ms245046(VS.80).aspx )。次の情報が含まれています。 :

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

そうは言っても、David Keanの最初のコメントは、懸念をより簡潔に要約したものであり、これは実際にはパフォーマンスの向上よりも正しいことのほうが重要だと述べています。

このルールはパフォーマンスの問題として分類されますが、メソッドを静的にすることによるパフォーマンスの向上は約1%にすぎません。むしろ、他のインスタンスメンバーを使用できないことにより、メンバーの不完全またはバグのいずれかを示す可能性のある、より正確な問題です。メソッドを静的にマークすると(SharedVisual Basicでは)、インスタンスの状態に触れないという意図が明確になります。

1
Scott Dorman

私は「プライベートメソッドのみを静的にする」キャンプにいます。パブリックメソッドを作成すると、望ましくない結合が導入され、テスト性が低下する可能性があります。パブリック静的メソッドをスタブすることはできません。

パブリック静的メソッドを使用するメソッドを単体テストする場合は、静的メソッドもテストすることになり、これが適切ではない場合があります。

1
Lennaert

それは場合によって異なりますが、通常、これらのメソッドを静的にすることはしません。コードは常に変化しており、おそらくいつかその機能を仮想化して、サブクラスでオーバーライドしたいと思うでしょう。あるいは、いつかインスタンス変数を参照する必要があるかもしれません。すべての呼び出しサイトを変更する必要がある場合、これらの変更を行うのは難しくなります。

1
Brian Ensink

これについて考える最善の方法は次のとおりです。クラスのインスタンスがインスタンス化されていないときに呼び出す必要があるクラスメソッドが必要な場合、またはある種のグローバルな状態を維持している場合は、staticをお勧めします。ただし、一般的には、メンバーを非静的にすることをお勧めします。

1
Foredecker

何らかの理由で静的でない静的メソッドは、単に煩わしいものです。ウィットするには:

銀行に電話して残高を要求します。
彼らは私の口座番号を尋ねます。
けっこうだ。インスタンスメソッド。

私は私の銀行に電話して、彼らの郵送先住所を尋ねます。
彼らは私の口座番号を尋ねます。
WTF?失敗-静的メソッドである必要があります。

1
I. J. Kennedy

一般的には、純粋な関数の機能的な観点から見ます。インスタンスメソッドである必要がありますか?そうでない場合は、ユーザーに変数を渡させて、現在のインスタンスの状態を変更しないようにすることでメリットが得られる可能性があります。 (まあ、あなたはまだ状態を壊すことができますが、ポイントは、設計上、そうしないことです。)私は通常、インスタンスメソッドをパブリックメンバーとして設計し、プライベートメンバーを静的にするために最善を尽くします。必要に応じて(後で他のクラスに簡単に抽出できます。

0
user29439