C#では#region
/#endregion
キーワードは、コード領域をエディターで折りたたみ可能にします。これを行うときはいつでも、おそらく他のクラスまたはメソッドにリファクタリングされる可能性のあるコードの大きなチャンクを隠すために行います。たとえば、管理しやすくするために、3行または4行の500行のコードを含むメソッドを見てきました。
では、リージョンの賢明な使用は問題の兆候ですか?私にはそうそうです。
コードのにおいは、バグの数を増やす可能性のあるデザインの問題があることを示す症状です。これは、リージョンには当てはまりませんが、長いメソッドのように、リージョンがコードのにおいを生み出す原因となる可能性があります。
以降:
アンチパターン(またはアンチパターン)は、ソーシャルオペレーション、ビジネスオペレーション、またはソフトウェアエンジニアリングで一般的に使用されているパターンですが、実際には効果がなく、逆効果です。
リージョンはアンチパターンです。コードの品質や読みやすさを向上させず、バグの数を減らしず、コードのリファクタリングをより複雑にするだけの可能性があるため、より多くの作業が必要です。
メソッドは短くする必要があります。メソッドに10行しかない場合、他の5行を操作するときに、リージョンを使用して5行を非表示にすることはおそらくないでしょう。
また、各メソッドは1つだけ実行する必要があります。一方、リージョンは、異なるものを分離することを目的としています。メソッドがA、Bの場合、2つの領域を作成することは論理的ですが、これは間違ったアプローチです。代わりに、メソッドを2つの個別のメソッドにリファクタリングする必要があります。
この場合、リージョンを使用すると、リファクタリングがさらに困難になる可能性があります。あなたが持っていると想像してください:
private void DoSomething()
{
var data = LoadData();
#region Work with database
var verification = VerifySomething();
if (!verification)
{
throw new DataCorruptedException();
}
Do(data);
DoSomethingElse(data);
#endregion
#region Audit
var auditEngine = InitializeAuditEngine();
auditEngine.Submit(data);
#endregion
}
最初の領域を折りたたんで2番目の領域に集中することはリスクが高いだけではありません。フローを停止する例外を簡単に忘れることができます(代わりにreturn
のガード句があり、これを見つけるのはさらに困難です)。ただし、コードを次のようにリファクタリングする必要がある場合にも問題が発生します。
private void DoSomething()
{
var data = LoadData();
#region Work with database
var verification = VerifySomething();
var info = DoSomethingElse(data);
if (verification)
{
Do(data);
}
#endregion
#region Audit
var auditEngine = InitializeAuditEngine(info);
auditEngine.Submit(
verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
#endregion
}
さて、リージョンは意味をなさず、最初のリージョンのコードを見ない限り、2番目のリージョンのコードを読んで理解することはできません。
私が時々見る別のケースはこれです:
public void DoSomething(string a, int b)
{
#region Validation of arguments
if (a == null)
{
throw new ArgumentNullException("a");
}
if (b <= 0)
{
throw new ArgumentOutOfScopeException("b", ...);
}
#endregion
#region Do real work
...
#endregion
}
引数の検証が数十のLOCにまたがるときに領域を使用するのは魅力的ですが、この問題を解決するより良い方法があります。それは.NET Frameworkソースコードで使用される方法です。
public void DoSomething(string a, int b)
{
if (a == null)
{
throw new ArgumentNullException("a");
}
if (b <= 0)
{
throw new ArgumentOutOfScopeException("b", ...);
}
InternalDoSomething(a, b);
}
private void InternalDoSomething(string a, int b)
{
...
}
一部の人々は、フィールドやプロパティなどをグループ化するためにそれらを使用しますこのアプローチは間違っています:コードがStyleCop準拠の場合、フィールド、プロパティ、プライベートメソッド、コンストラクターなどはすでにグループ化されており、簡単に見つけることができます。そうでない場合は、コードベース全体での均一性を保証するルールの適用について検討するときがきました。
他の人々は地域を使用して多くの類似したエンティティを隠します。たとえば、100個のフィールドを持つクラスがある場合(コメントと空白を数えると、少なくとも500行のコードが作成されます)、それらのフィールドを領域内に配置し、折りたたんで、それらのことを忘れたくなるかもしれません。繰り返しますが、これは間違っています。クラスに非常に多くのフィールドがあるので、継承を使用するか、オブジェクトをいくつかのオブジェクトにスライスすることを考える必要があります。
最後に、一部の人々は、領域を使用して関連するものをグループ化するように誘惑されます(そのデリゲートを持つイベント、またはIO IOに関連する他のメソッドなどを使用します。最初のケースでは混乱し、維持、読み取り、および理解が困難になります。2番目のケースでは、おそらくいくつかのクラスを作成するほうがよい設計になります。
いいえ。従来の使用方法:生成されたコード。それでも、コード生成ツールは、代わりに部分クラスを使用する必要があります。 C#でリージョンがサポートされている場合、それは主にこのレガシーの使用によるものであり、コードでリージョンを使用する人が多すぎるため、既存のコードベースを壊さずにリージョンを削除することは不可能です。
goto
と考えてください。言語またはIDEが機能をサポートしているという事実は、それを毎日使用する必要があることを意味するわけではありません。StyleCop SA1124ルールは明確です:使用しないでください地域ではありません。
現在、同僚のコードのコードレビューを行っています。コードベースには多くのリージョンが含まれており、実際には、リージョンを使用しない方法と、リージョンが不正なコードにつながる理由の両方の完璧な例です。ここではいくつかの例を示します。
4 000 LOCモンスター:
最近Programmers.SEのどこかを読んだところ、ファイルに含まれるusing
sが多すぎる場合(「未使用の使用を削除」コマンドを実行した後)は、このファイル内のクラスが多すぎることを示しています。同じことがファイル自体のサイズにも当てはまります。
コードを確認しているときに、4 000のLOCファイルを見つけました。このコードの作成者は、同じ15行のメソッドを何百回もコピーして貼り付け、変数の名前と呼び出されたメソッドをわずかに変更したようです。単純な正規表現では、いくつかのジェネリックを追加するだけで、ファイルを4 000 LOCから500 LOCにトリミングできます。より巧妙なリファクタリングにより、このクラスは数十行に削減される可能性があると確信しています。
リージョンを使用することにより、作者は、コードを維持することが不可能で不十分に記述されているという事実を無視し、コードをリファクタリングする代わりに大幅に複製することを奨励しました。
地域「Do A」、地域「Do B」:
もう1つの優れた例は、タスク1、タスク2、タスク3などを単純に実行するモンスター初期化メソッドです。完全に独立した5つまたは6つのタスクがあり、それぞれがコンテナークラスで何かを初期化しました。これらのタスクはすべて1つのメソッドにグループ化され、リージョンにグループ化されました。
これには1つの利点があります。
一方、問題は複数ありました。
地域間に依存関係があるかどうかは明らかではありませんでした。うまくいけば、変数の再利用はありませんでした。そうでなければ、メンテナンスはさらに悪夢になる可能性があります。
この方法をテストすることはほとんど不可能でした。一度に20の処理を実行するメソッドがそれらを正しく実行するかどうかを簡単に知るにはどうすればよいでしょうか。
フィールド領域、プロパティ領域、コンストラクター領域:
レビューしたコードには、すべてのフィールドを一緒にグループ化したり、すべてのプロパティを一緒にグループ化したりする多くの領域も含まれていました。これには明らかな問題がありました:ソースコードの増加です。
ファイルを開いてフィールドの膨大なリストを表示する場合、最初にクラスをリファクタリングしてから、コードを操作する傾向があります。リージョンでは、物事を折りたたみ、忘れることを習慣にします。
もう1つの問題は、どこにでもそれを行うと、1ブロックのリージョンを作成することになり、意味がありません。これは実際に、私がレビューしたコードの場合で、1つのコンストラクターを含む#region Constructor
がたくさんありました。
最後に、フィールド、プロパティ、コンストラクタなど すでに順序付けされている必要があります 。それらがあり、それらが規則(大文字で始まる定数など)に一致している場合、要素のタイプの停止位置とその他の開始位置はすでに明確であるため、そのための領域を明示的に作成する必要はありません。
何人が嫌いな地域が情熱的であるか、私には信じられないほどです!
私は彼らの反対意見の多くに完全に同意します。コードを#region
に入れて表示しないようにすることは悪いことです。クラスを別のクラスにリファクタリングする必要があるときに、クラスを#regions
に分割することは間違いです。 #region
を使用して冗長なセマンティック情報を埋め込むことは冗長です。
しかし、これらのいずれも、コードで領域を使用することに何かが本質的に間違っていることを意味します!ほとんどの人の異論は、他の人がIDEこのような機能を誤って使用する傾向があるチームで作業したことが原因であると考えられます。私は自分でプライマリーを使用する贅沢を持っています。リージョンが私のワークフローを整理するのに役立った方法です。たぶんそれは私の強迫性障害かもしれませんが、それがどれほどきちんと上品に書かれたとしても、一度に画面にたくさんのコードを表示したくありません。論理領域に入れると、私がコードを折りたたむことができますできませんI do気にします。不適切に記述されたコードは無視しません。それ以上にリファクタリングすることは意味がありません。追加の「メタ」編成は説明ではなく、無意味。
C++での作業に多くの時間を費やし、Windows APIに直接プログラミングするようになったので、リージョンのサポートがC#のサポートと同じくらい優れていることを願っています。別のGUIライブラリを使用すると、コードが単純または明確になり、画面から無関係なコードノイズを取り除く必要がなくなると主張できますが、それを望まない理由は他にもあります。キーボードとIDE=領域に分割されたコードの展開/折りたたみにかかる時間は1秒未満であることに十分に精通しています。意識的な焦点を制限するために、頭脳力を節約する時間私が現在取り組んでいるコードにのみ、それは価値がある以上のものです。すべてが1つのクラス/ファイルに属していますが、同時にすべてが画面に属しているわけではありません。
重要なのは、#regions
を使用してコードを分離し、論理的に分割することは、何としても回避すべき悪いことではないということです。 Edが指摘するように、それは「コードのにおい」ではありません。コードの匂いがする場合は、そのコードがリージョンからではなく、それらのリージョンに埋め込もうとしたコードからのものであることがわかります。機能があなたをより組織化するのに役立つか、より良いコードを書くのに役立つなら、私はそれを使うと言います。それが邪魔になるか、誤って使用していることに気付いた場合は、stopを使用します。最悪の事態が発生し、それを使用するユーザーとチームで作業する必要がある場合は、キーボードショートカットを覚えて、コードの概要をオフにします。 Ctrl+M、 Ctrl+P。そして文句を言うのをやめなさい。これは、「真の」、「ハードコア」プログラマーと見なされたい人たちが自分自身を試して証明したいという別の方法だと感じることがあります。構文の色分けを回避するよりも、領域を回避する方がよいでしょう。それはあなたをよりマッチョな開発者にするわけではありません。
言われていることはすべて、メソッド内の領域はまったくのナンセンスです。自分がそうしたいと思っているときはいつでも、別のメソッドにリファクタリングする必要があります。言い訳しない。
まず、「コードのにおい」という言葉はもう我慢できません。それはあまりにも頻繁に使用され、噛まれても良いコードを認識できなかった人々が投げかける時間の多くです。いずれかの方法...
私は個人的には多くの地域を使うのが好きではありません。それはコードを理解するのを難しくし、コードは私が興味を持っているものです。私は、頻繁に触れる必要がないコードの大きなチャンクがある場合、リージョンが好きです。それを除けば、彼らは私の邪魔をしているように見え、「プライベートメソッド」、「パブリックメソッド」などの領域は、私を夢中にさせるだけです。種類のコメントに似ていますi++ //increment i
。
また、テキストエディタのレイアウトではなくプログラムロジック/デザインパターンを表すために一般的に使用される用語であるため、領域の使用は実際には「アンチパターン」にはならないことも付け加えておきます。これは主観的です。あなたのために働くものを使用してください。リージョンを使いすぎているため、メンテナンス不可能なプログラムになってしまうことは決してありません。これがアンチパターンのすべてです。 :)
はい地域はコードのにおいです!
コンパイラーからリージョンが完全に削除されるのを見て嬉しいです。すべての開発者は、他のプログラマーにとって決して価値のない自分自身の無意味なグルーミングスキームを思い付きます。私は、赤ちゃんを飾り付けて美しくしたいプログラマーとすべて関係があります。本当の価値とは何の関係もありません。
「おい、私の同僚がここでいくつかの地域を使用したことを望んでいる」の一例を思い付くことができますか?
IDEを設定してすべての領域を自動的に拡張するように設定することはできますが、それらは依然として面倒であり、実際のコードの読み取りを妨げます。
私のすべてのパブリックメソッドが一緒にまとめられているかどうかに関係なく、私は本当にあまり気にしません。変数宣言と初期化の違いがわかったので、コードで表示する必要はありません。
価値のないグルーミング!
さらに、領域を使用してファイルのニーズと「情報アーキテクチャ」が必要な場合は、中心的な問題に対処する必要があるかもしれません。クラスが大きすぎます!それを小さな部分に分割することははるかに有益であり、適切に行われると、真の意味論/可読性が追加されます。
私は、さまざまなタイプのメソッドまたはコードの一部をグループ化する方法として、リージョンを個人的に使用しています。
したがって、コードファイルを開くと、次のようになります。
メソッド内にリージョンを配置しません。コードの匂いの兆候である私見。私はかつて1200行を超える長さのメソッドに出くわし、その中に5つの異なる領域がありました。怖い光景でした!
他の開発者が物事をすばやく見つけることができるようにコードを整理する方法としてそれを使用している場合、問題の兆候ではないと思います。メソッド内のコード行を非表示にするためにそれを使用している場合、そのメソッドを再考するときがきたと思います。
#region
ブロックを使用して非常に大きなクラスを読み取り可能にすることは、通常、単一責任の原則に違反していることを示しています。それらが動作をグループ化するために使用されている場合、それは可能性が高いもクラスが過度に実行していることです(もう一度SRPに違反しています)。
「コードのにおい」という考え方に固執すると、#region
ブロックはそれ自体がコードのにおいではなく、においを隠そうとするという点で、より「コードの臭い」になります。私は過去にそれらを大量に使用したことがありますが、リファクタリングを開始すると、あまり隠されていないため、ほとんど表示されなくなります。
ここでのキーワードは「賢明」です。メソッド内に領域を置くことが賢明である場合を想像するのは難しいです。それはコードを隠したり怠惰であったりする可能性が高いです。ただし、コードのあちこちにいくつかの領域があることには、十分な理由がある場合があります。
リージョンがたくさんあるとしたら、コードのにおいだと思います。リージョンは多くの場合、将来のリファクタリングの可能な場所のヒントになります。地域がたくさんあるということは、誰かがヒントを実際に取ったことがないということです。
慎重に使用すると、多くのメソッドを持つ単一のクラスの構造と、それぞれに数個のメソッドしかない多くのクラスの構造の間に適切な中間点が与えられます。これらは、クラスが複数のクラスにリファクタリングされる必要があるポイントに近づき始めたが、まだ完全ではない場合に最も役立ちます。関連するメソッドをグループ化することにより、関連するメソッドのセットが独自のクラスに簡単に抽出できるようにします。たとえば、500行のコードに近づいているクラスがある場合、ある領域で合計200行のコードをまとめて使用するその一連のメソッドは、おそらく何らかの方法でリファクタリングするのに適した部分です。メソッドも良いターゲットかもしれません。
リージョンを使用する別の方法は、大きなメソッドをリファクタリングすることの悪影響の1つを減らすことです。多くの小さくて簡潔で簡単に再利用できるメソッドは、読者がスクロールして、ほとんど関係のない別のメソッドにアクセスする必要があります。リージョンは、メソッドとそのヘルパーをリーダーにメタカプセル化する良い方法です。そのため、クラスの別の側面で作業している人は、それらを折りたたみ、コードのその部分をすぐに閉じることができます。もちろん、これが機能するのは、リージョンが本当によく整理されていて、本質的にコードを文書化する別の方法として使用されている場合のみです。
一般に、リージョンは自分を整理し、コードを「文書化」するのに役立ち、リージョンを使用しない場合よりもはるかに早くリファクタリングする場所を見つけるのに役立ちます。
主にCRUDサーバークラスのリージョンを使用して、さまざまなタイプの操作を整理しています。それでも私はそれらなしで喜んで行くことができました。
広範囲に使用すると、赤信号が発生します。責任感のある授業を探しています。
私の経験では、コードが数百行あるメソッドは間違いなくにおいです。
私の経験則は:ファイルに5つ以上の領域がある場合、それはコードのにおいです
つまり、フィールド、メソッド、プロパティ、コンストラクターの輪郭を描くのは問題ないかもしれませんが、他のすべてのメソッドをそれ自体の領域にラップし始めている場合、何かが深刻に間違っています
..そしてはい、私は多くのプロジェクトに携わってきました。そのようなケースは、コーディング標準、コード生成、またはその両方が不十分なことが原因です。コードの概要を把握するために、Visual Studioですべてのアウトラインを切り替える必要があるのは古くからあります。
地域で使用
以前は、Windowsフォームアプリの「ハンドコーディング」インターフェースイベントに個人的に使用しました。
ただし、私の作業では、SQLの処理にコードジェネレーターを使用し、リージョンを自動的に使用して、選択、更新、削除などの種類のメソッドを分類しています。
したがって、私はそれらを頻繁に使用しませんが、大きなコードのチャンクを削除するのに完全に適しています。
リージョンがある場合[〜#〜] in [〜#〜]コードには、確かに問題があります(生成されたコードの場合を除いて)。リージョンをコードに置くことは、基本的に「これをリファクタリングする」と言います。
ただし、他の場合もあります。私がしばらく前にやったことを思い出すもの:数千の事前計算されたアイテムが含まれているテーブル。これはジオメトリの説明であり、表のエラーがない限り、それを見る機会は決してありません。もちろん、リソースなどからデータを取得することもできますが、コンパイラを使用して読みやすくすることはできません。
「コードの匂い」だと思います。
アンチパターンは一般にソフトウェアの基本的な構造上の問題ですが、リージョン自体はエディタで不愉快な動作を引き起こします。リージョンの使用は本質的に悪いわけではありませんが、特にコードのチャンクを非表示にするためにリージョンを多く使用することは、他の場所で起こっている他の独立したより大きな問題があることを示している可能性があります。
最近のプロジェクトでは、いくつかのリージョンが埋め込まれた1700ライン法がありました。興味深いのは、メソッド内で行われていた個別のアクションをリージョンが区切っていることです。コードの機能に影響を与えることなく、各領域でリファクタリング->抽出メソッドを実行できました。
一般に、ボイラープレートコードを非表示にするために使用される領域は便利です。プロパティやフィールドなどを非表示にするために領域を使用することはお勧めしません。クラス内で作業するときに領域が扱いにくい場合は、おそらくクラスをさらに分解する必要があるためです。ただし、ハードルールとして、メソッド内にリージョンを配置する場合は、そのブロックをリージョンでラップするよりも、何が起こっているかを説明する別のメソッドを抽出する方がよいでしょう。
良質のコードでリージョンを使用できますか?多分。彼らは、多くの場合そうであるに違いない。しかし、私の個人的な経験は私を非常に疑わしいままにします-私はほとんど独占的に誤用されている地域を見てきました。私はイライラしていると言いますが、それでも楽観的です。
これまで見てきたリージョンを使用するコードは、次の3つのカテゴリに大まかに分類できます。
因数分解されたコード:私が見たコードのほとんどは、貧しい人の因数分解ツールとして領域を使用しています。たとえば、クラスをさまざまな目的に特化するのが理にかなっているところまで成長した場合は、代わりに、目的ごとに1つずつ、別々の領域に分割できます。
問題のドメインに対して誤ったライブラリー、時には間違った言語を使用して書かれたコード多くの場合、プログラマーが問題のドメインに適切なライブラリーのセットを使用していないと、コードが非常に冗長になり、多くの小さなヘルパー関数が表示されますこれは実際には属していません(おそらく独自のライブラリに属しています)。
学生または最近の卒業生によって書かれたコード。いくつかのプログラムやコースは、あらゆる種類の奇妙な目的のために地域を使用することで、学生に教え込もうとするようです。リージョンタグとコード行の比率が1:5以下の範囲になるまで、ソースコードが散らかっているリージョンが表示されます。
リージョンを使用するのは1つだけです(少なくとも、他の場所を使用することは考えられません)。メソッドの単体テストをグループ化するためです。
通常、クラスごとに1つのテストクラスを用意し、メソッドの名前を持つリージョンを使用して、各メソッドの単体テストをグループ化します。それがコードの匂いか何かかどうかはわかりませんが、基本的な考え方は、ユニットテストはコード内の何かが変更されたために壊れない限り変更する必要がないということなので、特定のメソッドのすべてのテストを見つけやすくなりますかなり早く。
過去にリージョンを使用してコードを整理したことがあるかもしれませんが、最後に行ったのが思い出せません。ユニットテストのクラスでは自分の地域に固執します。
私はそれが反パターンであると信じており、率直に言ってそれらは排除されるべきだと思います。しかし、それらが標準のVisual Studioである場所で作業するという不幸な状況にある場合は、リージョンが表示されるたびに吐きたい量を最小限に抑えるための素晴らしいツールを提供します I Hate #Regions
このプラグインは、領域のフォントサイズを非常に小さくします。それらも拡張されるため、ctr + m + lを押してすべてのリージョンを開く必要はありません。この形式のコードガンは修正されませんが、耐えられるようになります。
リージョンは気の利いた組織的なアイデアでしたが、すべてを過剰に分類したい開発者の傾向を考慮に入れることができませんでした、そしてほとんどの現代の今日では一般的に不必要ですOOP実践...それらは「匂い」です、それらを使用すると、多くの場合、クラス/メソッドが大きすぎてリファクタリングする必要があることを示すという意味で、SOLIDの原則のSに違反している可能性があるため...臭い、それは必ずしも必要ではありません何かが悪くなっていることを意味します。
リージョンは、オブジェクト指向コードであるIMOよりも機能コードでより多くの目的を果たします。IMOでは、シーケンシャルデータの長い関数があり、分割することが理にかなっていますが、C#で個人的に使用したことがあり、ほとんど常に見たくない/見たくないコードに集中する。私にとって、これらは通常、NPocoまたはそのバリアントに使用されるコードベースの生のSQL文字列定数でした。 ORMを介してPOCOオブジェクトにデータを入力する方法を実際に気にしない限り、これらを確認してもまったく意味がありません...気にした場合は、領域を拡張してBAM! 150行以上の複雑なSQLクエリが表示されます。
リージョンを使用して、可視性とメンバータイプの各組み合わせを含めています。したがって、すべてのプライベート関数はリージョンなどに行きます。
これを行う理由は、コードを折りたたむことができるようにするためではありません。エディターへの参照を挿入して、プロキシへの参照を挿入できるようにするためです。
#region "private_static_members"
/// <summary>
/// cache for LauncherProxy
/// </summary>
private static LauncherProxy _launcherProxy;
#endregion
#region "protected_const_properties"
protected LauncherProxy LauncherProxy{
get{
if(_launcherProxy==null) {
if (!God.Iam.HasProxy(LauncherProxy.NAME)) {
God.Iam.RegisterProxy(new LauncherProxy());
}
_launcherProxy=God.Iam.Proxy(LauncherProxy.NAME) as LauncherProxy;
}
return _launcherProxy;
}
}
#endregion
コードに入れ、各部分を適切な領域にきちんとはめ込みます。
この場合、マクロによってプロジェクトが分析され、プロキシのリストボックスが表示され、必要なコードが挿入されます。カーソルが動かない。
C#の学習の初めに、共通性を維持するためにリージョンを使用することを検討しましたが、それは常に1対1の関係ではないため、ヒットとミスの命題です。 2つの地域で使用されているメンバーに不安を感じたり、これらの条件に基づいて事態を分割したりすることを望む人。
他の唯一のタイプの分離はメソッドです。メソッドをコマンド、関数、およびハンドラーに分割します。そのため、パブリック、プライベートなどのコマンドなどの領域があります。
これは私に粒度を与えますが、一貫しています不明確信頼できる粒度。
領域はプリプロセッサ式です。つまり、領域はコメントのように扱われ、基本的にコンパイラーによって無視されます。これらは、純粋にVisual Studioで使用されるビジュアルツールです。したがって、#regionはコードではないため、実際にはコードの匂いではありません。コードのにおいは、800行のメソッドであり、さまざまな責任が埋め込まれています。つまり、1つのメソッドに10の領域が表示されている場合、おそらくコードのにおいを隠すために使用されています。とは言っても、非常に効果的に使用されて、クラスが目に心地よくなり、ナビゲートしやすくなりました-非常によく記述された構造化クラスでも!