web-dev-qa-db-ja.com

C#の別のクラス内で宣言されたクラス

私はいくつかのレガシーコードに取り組んでいますが、わからないことがあります。別のclass y内で宣言されているclass xがあります。 Class yclass xの内部でのみ使用されますが、別のクラスファイルを作成し、class y内で宣言するのではなく、そこにclass xを配置しないのはなぜですか?これはOOPに違反しているのではなく、このクラス内でのみ使用されるため、スタイルの問題ではありません。このコードの一部をリファクタリングしていますが、最初の反応は、class yを独自のファイルに分離することです。

namespace Library
{
   public class x
   {
      // methods, properties, local members of class x

      class y
      {
         // methods, properties, local members of class y
      }
   }
}
47
Jeremy Cron

内部クラスは、クラスxのスコープ内でのみ使用され、クラスxのファクタリング/アーキテクチャに論理的に適合するため、内部クラスを作成します。

クラスyは、一般に知られることを意図していないクラスxの実装の詳細にも関与する場合があります。

60
plinth

これにはパーミッションの意味があります。最上位の「クラスy」は「内部」になりますが、ここで「y」は「x」に対してプライベートです。このアプローチは、実装の詳細(キャッシュ行など)に役立ちます。同様に、yxのすべてのプライベート状態にアクセスできます。

ジェネリックとの関係もあります。 x<T>.yは、「T」の汎用であり、外部クラスから継承されます。 BarTを完全に使用しているので、Barの静的フィールドはTごとにスコープされていることに注意してください。

class Foo<T> {
    void Test(T value) {
        Bar bar = new Bar();
        bar.Value = value;
    }
    class Bar {
        public T Value { get; set; }
    }
}

多くの場合、人々はBarBar<T>として定義する必要があると誤って考えています-これは(事実上)doublyジェネリック-つまりFoo<TOld, T>-TOldは(現在使用不可)T from Foo<T>です。だからそれをしないでください!または、wantが二重にジェネリックである場合は、異なる名前を選択してください。幸いなことに、コンパイラはこれについて警告します...

20
Marc Gravell

このコードは、「クラスyはクラスxの内部でのみ使用される」という正確な理由で問題ありません。これらは ネストされた型 であり、それらを使用するためのガイドラインの1つは、ネストされた型を宣言型に密結合する必要があり、汎用型として有用であってはならないことです。このように、ネストされたクラスは他のクラスにはアクセスできませんが、それでもオブジェクト指向の原則に従うことができます。

7
Pawel Krakowiak

含まれているクラスがユーティリティとしてのみ使用されている限り、大丈夫だと思います。たとえば、この種の構造を使用して、プライベートメソッドの複雑な戻り値の型を定義します。

2
phatoni

更新中のコード(および最初に作成したコード)を調べて、すべてのネストされたクラスを削除しました。あいにく、私は元々、定義されたクラスの外側でネストされたクラスを使用しました。ネストされたクラスを移動することは、もともとデザインが悪かったため、大きな違いをもたらしました。

YがXでのみ使用され、Xの外部で使用されることがない場合は、そのままにしておきます

2
Dan McClain

この種のアーキテクチャが適切な場合を明確にするネストされたクラスの使用例を紹介しましょう。最近、データテーブルから選択した列を取得し、「ピボット」して、行が列に、またはその逆になるようにHTMLテーブルを生成する必要がありました。私の場合、データのピボットとかなり複雑な出力の生成という2つの基本的な操作がありました(データを表示するだけではありませんでした。各データ列/テーブル行は、タイトルの抽出、イメージタグの生成、リンクの設定、など。したがって、SQL Pivotを使用することも正しくありませんでした)。

1つのクラスを作成して全体を実行しようとした最初の試みの後、データ/メソッドの多くがヘッダー処理、行処理、ピボットの3つの異なるパーティションに分類されることを認識しました。したがって、「ヘッダー」と「行」のロジックを別々のネストされたクラスにカプセル化することをお勧めします。これにより、各行が保持するデータを分離し、ピボット操作を非常にきれいにプログラムできました(データテーブルの各列に個別の行オブジェクトを呼び出す)。ピボット操作の最後に、ヘッダーオブジェクトを呼び出して出力を生成し、次に各行オブジェクトを順番に呼び出して、メインクラスに出力を生成しました。

A)ネストされたクラスにはマスタークラスからのデータが必要であり、B)処理は非常に具体的で他の場所では役立たないため、個別のクラスは適切ではありませんでした。 1つの大きなクラスをプログラミングするだけでは、「列」や「行」など、データとHTML出力のどちらを話しているかによって異なる用語を取り巻く混乱のため、単に厄介でした。また、ビジネスクラスでHTMLを生成していたという点で、これは珍しい作業であったため、UI生成から純粋なビジネスロジックを引き離したかったのです。最終的に、ネストされたクラスはカプセル化とデータ共有の完璧なバランスを提供しました。

2

クラスyを別のファイルにリファクタリングすることもできますが、parialクラスを使用します。この利点は、ファイルごとに1つのクラスがまだあり、クラスxの外側に宣言を移動するリファクタリングの手間がかからないことです。

例えば次のようなコードファイルx.y.csを作成できます。

partial class X
{
    class Y
    {
        //implementation goes here
    }
} 
1
Matthew Dresser