なぜ部分クラスを使用するのですか?


72

私の理解では、このpartialキーワードはクラスを複数のソースファイルに分割することを許可するだけです。コードの整理以外にこれを行う理由はありますか?生成されたUIクラスで使用されているのを見ました。

キーワード全体を作成するのは不十分な理由のようです。クラスが複数のファイルを必要とするのに十分な大きさである場合、おそらくあまりにも多くのことを行っています。どこかで完了させる別のプログラマーのためにクラスを部分的に定義するために使用できると思いましたが、抽象クラスを作成する方が良いでしょう。


10
それは、実際には「キーワード全体」でもありません。それは文脈上のキーワードです。partialそれは前に来るときにのみ意味しますclass。あなたは、コードなどの他の部分の識別子名として使用することができます
ディーン・ハーディング

4
それらを使用し、生成されたコード用ではない場合、私はあなたを嫌います。個人的にではなく、一般的に。部分クラスを介してコードを探し出すのは嫌いです。
スティーブンエバーズ

3
「コードを探し出す」のは難しくありません。VSのドロップダウンには、パーシャルのどの部分を見ているかに関係なく、すべてのクラスメソッドが表示されます。他のコードナビゲーションも正常に機能します(「巧妙な」R#スタイルのナビゲーションまたは古き良きshift-ctrl-fのいずれか
スティーブ

2
部分クラスは別のファイルにある必要があるという誤解です。
バート

回答:


110

生成されたクラスを継承せずに生成されたコードにカスタムロジックを追加できるため、クラスの一部がカスタムツールによって生成されるすべてのシナリオで非常に役立ちます。ところで 同じ理由で部分的な方法もあります。

UIだけでなく、Linq-To-SqlやEntity Frameworkなどの他のテクノロジーもこれをかなり頻繁に使用しています。


44
また、生成されたコードをバージョン管理から外し、コードをバージョン管理下に保つことができます。
フランク・シーラー

3
良い点、私はそれについて考えたことがない。しかし、実際にそれが悪用されているのを見たことがあります。(お粗末な)プログラマーがファイルサイズを管理しやすい状態に保つ方法。
マーティンウィックマン

1
私が使用した最良の例は次のとおりです。a)クラスを拡張するLinq to SQLデータコンテキストの場合。b)Webサービスから渡されたクラスを拡張します。どちらの場合もこれは悪用でもなければ、ファイルサイズを管理しやすくするための手段でもありません...それがそのように使用されるのを見ると、私は根本的に不満です(そしてステップを踏むでしょう...)
Murph

3
WinFormクラスは、コントロールを作成するすべてのデザイナーコードを非表示にするために使用します(特に重要なのは、デザイナーが作成するすべてのコードをランダムに並べ替えて、diff / blaming時に大きな混乱を引き起こすためです)。また、XMLを使用している場合、XSDツールはスキーマファイルから部分クラスを再度作成して、自動生成された並べ替えからコードを分離できるようにします。
ダン・ニーリー

2
@MartinWickmanは必ずしもお粗末なわけではありません。これは、レガシーコードでGodオブジェクトをリファクタリングするための良い出発点です。まず、大きなクラスを別々のファイルに分割して、風景をきれいにしてください。(私はあなたのコメントが非常に古いことを知っています)
コンラッド・モラウスキー14

26

あなたが言うように、それはしばしば生成されたコードを分離するために使用されます。多くの場合、クラス/ファイルのサイズとは無関係です。

生成されたコードを分離する利点は、スタイルの1つです。生成されたコードは非常にくて読みにくいことがあり、多くのコーディング標準(およびStyleCopチェック)に失敗しますが、それで問題ありません。したがって、別のファイルで「非表示」にすると、クラスの残りの部分が標準に達していること、StyleCopチェックに合格することなどに集中できます。

私がそれを使用した別の領域は、クラスが複数のインターフェイスを実装する場所です。実装を個別のファイルに分けることは非常に素晴らしいことがありますが、これは個人的な好みの問題ですが、コーディング標準が必要とすることは見たことがありません(または防止)これ。


9
インターフェイスの実装を分離するためにクラスのパーシャルを使用することを考えたことがありません。これは素晴らしいアイデアです。
マークブース

それはスタイル以上のものです。コードジェネレーターの開発者は、ジェネレーターによって管理されるファイル内のコードを編集できるようにするためにフープをジャンプする必要があり、それでも問題が発生します。私にとって一番のメリットは、ジェネレーターが触れる/できないコードを書く場所を提供することです。これはかなり具体的なメリットです。
ダニエル

19

私が働いている開発者の1人は、数週間前に、制御不能になり、多くのパブリックメソッドを持つ巨大な神のクラスのリファクタリングでかなり使い道ができました。クラスを個別の部分クラスに分割すると、既存の機能を損なうことなく、クラスである必要のあるよりアトミックなユニットにクラスを物理的に分離でき、一般的なものとそうでないものを確認できます。これを最初のステージとして使用すると、パーシャルを独自の独立したクラスに簡単に分割し、コードベース全体に実装できます。これはいいアイデアだと思いました。

ただし、一般的には、新しいコードを作成するときに、マシン生成クラスを強化するためにのみ使用すべきだと思います。


1
私はそれがどのように役立つかを見ることができます。それが言語であることが正当であるかどうか...私は知りません。ただし、マシン生成コードの別の話です。
マイケルK

2
はい、それが言語である理由ではありませんが、それらを使用する興味深い方法です。

18

パーシャルが理にかなっているいくつかの有用なシナリオを考えることができます。それらのほとんどは自分のプロジェクトで使用しています。

  • 保守しているコードからTool / IDE / Designer生成コードを分離するため。良い例は、Form.Designer.csWindowsフォームアプリケーション用にデザイナーが生成したコードを含むファイルです。他の多くの.NET形式にもツールで生成されたコードがあり、プロジェクトのビルド時に再生成される可能性があるため、すべてのカスタム変更がスワイプされます。分離することで、このような自動化された変更からコードと変更を安全に保つことができます。

  • 実装に多くのコードを含む複数のインターフェイスを実装する場合。このようなインターフェイスごとに個別の部分ファイルを使用し、次のように名前を付ける傾向があります{Class}.{Interface}.cs。IDEでどのインターフェイスが{Class}どのように実装されているかを簡単に確認できます。

  • クラスに1つ以上のネストされたクラスを含める必要がある場合(特に、別のファイルに入れるのに十分なコードが含まれている場合)。上記のパターンに固執し、{Class}.{NestedClass}.csネストされたクラスごとに命名規則を使用します。同様の方法は、Virtlinkの回答ですでに言及されています

  • 拡張メソッドstaticを保持するクラスを作成するとき。多くの場合、同じ拡張メソッドロジックを類似のクラスまたはインターフェイスに提供することがよくあります。たとえば、ジェネリックコレクションと非ジェネリックコレクションの場合です。単一のクラスまたはインターフェイスのすべての拡張メソッドを、静的クラスの別の部分に配置します。たとえば、インターフェイスのすべての拡張メソッドを1か所に、同じメソッドを別のファイルに持っています。別のアプローチは、同じメソッド(そのオーバーロードのすべて)を同じパーシャルに配置し、パラメーターのすべての可能なクラスを使用することです。ReverseIListIList<T>thisReverse1つのファイルでの実装。それは、コード量の観点から分離を正当化する方が良いか、またはあなたまたはあなたの組織が固執するかもしれないいくつかの内部規則に依存します。

  • 私はこれを使用しませんが、ここで説明するアプローチを好むC / C ++の人々を見てきました:部分メソッドのみでクラスの部分を作成します。これは、インターフェースを定義し、メソッド宣言を実装から分離するC / C ++の方法に似ています。

  • 純粋に論理的な懸念による分離。それ自体で複数の論理操作セットを結合する大規模なクラスで作業する場合は、論理的に関連する各コードを個別のパーシャルに分離できます。通常、このようなクラスの存在は、関心の分離の原則に反しますが、特に古いコードベースでは、実際のケースでよく見られます。仲間のユーザーSteve Eversは、この質問への回答でそれらを言及し、それらをgod objectsという名前で参照しています。私は個人的に部分クラスのアプローチを使用して、このような本当に大きなファイルのリファクタリングが行われる前にコードを分割して、作業を容易にし、リファクタリングをより透明にします。これにより、SVNのようなバージョン管理システムが関与している場合に発生する可能性のある競合も軽減されます。


14

誰からも言及されたことはありませんpartial。ネストされたクラスを独自のファイルに配置するために使用しています。

すべてのコードファイルには、クラス、構造体、インターフェイス、または列挙が1つだけ含まれています。ファイル名に探しているものの名​​前が表示されている場合、オブジェクトの定義を見つけやすくなります。また、Visual Studioはプロジェクトフォルダーを名前空間に一致させようとするため、ファイル名はクラスに一致する必要があります。

これはまた、NestedClass内部MyClassにネストされたクラスが私のプロジェクトでそれ自身のファイルを持つことを意味します:MyClass.NestedClass.cs

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}

1
なぜこの答えに反対票を投じるのだろうか。前述のプラクティスはアンチパターンではなく、私が知っている問題を引き起こすこともありません。
イヴァイロスラヴォフ14

1
これにより、クラスファイルを(コードの行数に関して)小さく保ちながら、内部クラスに属するコードを適切にカプセル化することもできます。
redcalx

10

生成されたコードを使用しての例外を除いて、私がしているだけで、これまで彼らはのためにカバーするために努力に使わ見神オブジェクト。新しいコードベースを理解したり、同じオブジェクトである複数のソースファイル間を移動したりするのは面倒です。

だからあなたがWhy use partial classes?私に答えるとき、あなたが生成されたコードを使用しているのでなければ、しないでください。


+1。これらのタイプのオブジェクトが名前(神オブジェクト)と呼ばれるのは初めてです。公式でもあります。新しいことを学ぶのに遅すぎることはありません。
イヴァイロスラヴォフ14

6

コードの構成が唯一の理由ですが、最初に思われるよりも深くなります。部分が生成される部分クラスがある場合、簡単にできます:

  • 書き込み先のクラスの手動変更を検出することなくコードを再生成します(これらの部分を上書きしないようにします)。
  • 生成された部分クラスをテストカバレッジ、ソース管理、メトリックなどから除外します。
  • 生成されたコードを使用して、継承戦略をそれに基づいて強制する必要はありません(他のクラスから継承できます)。

1

生成/暗黙のクラスが部分的に宣言されている場所もいくつかあります。そのため、開発者がクラスを拡張する必要がある場合、場所全体を継承してオーバーライドすることなく、フルアクセスできます。いくつかの例をキャッチしようとする場合は、IISで初めてwebformsサイトを実行した後、asp.net temp領域で生成されたクラスを見てください。


1

私はそれらの汚い使用を考えることができます。

共通の機能を必要とするクラスがいくつかあるが、それらの機能をそれらの上位の継承チェーンに注入したくないとします。または、共通のヘルパークラスを使用する一連のクラスがあります。

基本的に、複数の継承を行いたいが、C#は好まない。したがって、あなたが行うことは、部分的にC / C ++で本質的に#includeであるものを作成することです。

すべての機能をクラスに入れるか、ヘルパークラスを使用します。次に、ヘルパーをX回コピーし、名前を部分クラスA、B、Cに変更します。A、B、Cクラスに部分的に配置します。

免責事項:はい、これは悪です。特に他の人があなたを怒らせるなら、絶対にやらないでください。


ミックスイン。これは...マニュアルのコピーを避けるために、T4と組み合わせることができる
ピーター・テイラー

前述のように、これはミックスインによく似ています。ただし、「特性」と呼ばれる概念に近づいているため、達成しようとしていることを安全に処理できます。私はpublius-ovidius.livejournal.com/314737.htmlで言語にとらわれない説明を 持っています。
オウィディウス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.