静的である可能性があるC#メソッドは静的である必要がありますか?[閉まっている]


103

静的にできる C#メソッドは静的でなければなりませんか?

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

問題は、それは静的である必要がありますか?これは、設計や選択によって静的ではなく、インスタンス値を参照しないという性質上、単純です。



41
「かなり正確」は矛盾です
マット・ブリッグス

1
ツールのVisual StudioツールであるResharperは、そう言っています!:-)
レベッカ

@Juntoたぶんあなたのバージョンかもしれませんが、私のものは静的にできると言います...
ロビー・ディー

回答:


59

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

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

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

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

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

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

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

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

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

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

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

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


43

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

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

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


6
同意した。私は通常、このような場合にメソッドを「プライベートスタティック」にします。
harpo

6
プライベートスタティックも想定していません。主なことは自問することです。このメソッドはこのタイプの一部として論理的に適合しますか、それとも便宜上ここだけですか?後者の場合、どこか他の場所にうまく収まるでしょうか?
Joel Coehoorn、2009

1
のように:「新しいメソッドは論理的に別の場所に属することができますか?」-手がかりは、それがローカル状態に依存していないことです。
AndyM

20

必ずしも。

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


彼は主に私的な方法に言及していると思います
ジョージ・マウアー

@Ray-そうです、これは非プライベートメンバーにのみ適用されます。私はこれを反映するために私の答えを更新しました。
マイケル

私の考えを正確に-あなただけのために可能性が .....何かの静的はあなたがする必要があるわけか、すべきではありません作る
marc_s

それでは、静的にすることができるプライベートメソッドに対して何をしますか?
レイ

@Ray-多分、静的に移行する十分な理由があるまで、そのままにしておきます。
マイケル

13

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


11

はい、そうです。様々ながあるカップリングのメトリクスメソッド静的を作るなど、他のクラス、メソッド、のように、あなたのクラスは他のものにどのように依存するかという尺度は、あなたがすることができるため、ダウン結合度を維持する方法であることを確認静的メソッドは、任意の参照していませんメンバー。


7
必ずしも。静的メソッドは、あなたが言ったように、インスタンス情報やメンバーにはアクセスしませんが、他のクラスや他の一般的なメソッドと対話することができます。静的であることは、必ずしも結合が減少することを意味しません。しかし、私はあなたの要点を理解しました。
ビクターロドリゲス

代わりに、静的な実際カップリングを増加させます。これは、静的な方法に限定されているため、たとえば、それをイベライドする方法がないため、動作を変更する方法がないためです。
HimBromBeere 2017

8

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


6

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

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

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

ええ、ぜひやってみてください。


1
静的メソッドは引き続き状態にアクセスできます。渡されたオブジェクトから状態を取得するだけです。逆に、インスタンスフィールドには必ずしも変更可能な状態が含まれているわけではありません。
ヨルゲンFogh

6

静的メソッドは非静的メソッドよりも高速であるため、そうです。可能な場合は静的メソッドでなければならず、非静的のままにする特別な理由はありません


3
それは技術的には真実ですが、実際の物質的な意味ではありません。static / nonの違いがパフォーマンスの要因となることは非常にまれです。
フォレデッカー2009

22
-1:教科書の時期尚早の最適化。一般的なケースで静的か非静的かを決定するときは、速度が最初の基準ではないはずです。
わからない

2
わからないことに同意します。これが静的かそうでないかを検討する最後の理由になるはずです。
サミュエル

5
私のポイントは、速度が99%の場合に関数が静的であるか非静的であるかを決定するための最も悪い理由の1つです。OOの設計に関しては、他の投稿で詳しく説明しているはるかに重要な考慮事項があります。
わからない

2
@agnieszka:通常、静的メソッドではなくインスタンスメソッドを使用する特別な理由は状態です。メソッドを静的のままにしておくと、複雑なアプリケーションで、髪を引き裂くようなバグが発生します。グローバルな状態、競合状態、スレッドセーフなどの
変更を検討してください

5

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

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

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

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


4

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

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

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


4

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


2

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


1
ReSharperの設定は変更できます:P
Bernhard Hofmann

1
それがとても簡単だったら、Resharperからの摩耗はありませんでした...今まで:)
Prankster

1

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


ええ、でも、いつかこれを行う必要がある場合は、常に静的にしないでください。それとも何か不足していますか?
レイ

1
@レイ-私は私の答えでこれをカバーします。staticからnon-staticは重大な変更であるため、すべてのコンシューマーを変更する必要があります。小さなプログラムでは大したことではありませんが、それが他の人が使用するためのライブラリである場合、これを考慮に入れる必要があります。
マイケル

すべての呼び出しサイトは、静的メソッド呼び出しからメンバー関数呼び出しに変更する必要があります。
ブライアンエンシンク2009

申し訳ありませんが、私のコメントの後に追加しました。私の考えではプライベートメソッドについて考えていましたが、それはパブリックメソッドの有効なポイントです。
レイ

...またはいつかそれを捨てることができます。これらの引数は、メソッドを非静的にするのに十分ではありません。
agnieszka 2009

1

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


1

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

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

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

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

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

コード:

public static void Reverse(Array array)

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


数学は悪い例です。私はそれが良いと思います:newnumber = Math.round(number)よりもnewnumber = number.round(2)
グラフィク

3
Mathクラスは、静的クラスを使用する完璧な例です。それがこのトピックに関するものであり、数値の丸め方についてではありません...
KdgDev 2009

1

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

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

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

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


1

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

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

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


1

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

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


1

なんらかの理由で非静的にされている本質的に静的なメソッドは単に煩わしいものです。ウィットするには:

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

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


1
異なる顧客が異なるブランチでサービスを提供している場合はどうなりますか?銀行の本店に郵送で郵送すると、最終的には適切な支店に届く可能性がありますが、それは、顧客にサービスを提供する特定の支店のアドレスを使用しても、顧客により良いサービスが提供されないという意味ではありません。
スーパーキャット

0

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


-1

これらの場合、私はメソッドをstaticまたはutilsライブラリに移動する傾向があるため、「オブジェクト」の概念と「クラス」の概念を混同しないでください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.