241

C# のネストされたクラスについて理解しようとしています。ネストされたクラスは、別のクラス内で定義されたクラスであることを理解しています。私が得られないのは、これを行う必要がある理由です。

4

8 に答える 8

284

私が特に気に入っているパターンは、ネストされたクラスとファクトリ パターンを組み合わせることです。

public abstract class BankAccount
{
  private BankAccount() {} // prevent third-party subclassing.
  private sealed class SavingsAccount : BankAccount { ... }
  private sealed class ChequingAccount : BankAccount { ... }
  public static BankAccount MakeSavingAccount() { ... }
  public static BankAccount MakeChequingAccount() { ... }
}

このようにクラスを入れ子にすることで、第三者が独自のサブクラスを作成できないようにしています。bankaccount オブジェクトで実行されるすべてのコードを完全に制御できます。そして、すべてのサブクラスは、基本クラスを介して実装の詳細を共有できます。

于 2009-07-05T15:20:18.277 に答える
124

通常、その目的は、ネストされたクラスのスコープを制限することだけです。通常のクラスと比較して、ネストされたクラスには、private修飾子の追加の可能性があります (protectedもちろん)。

基本的に、このクラスを「親」クラス内からのみ使用する必要がある場合 (スコープの観点から)、通常はネストされたクラスとして定義するのが適切です。このクラスをassembly/library なしで使用する必要がある場合は、通常、2 つのクラス間に概念的な関係があるかどうかに関係なく、別の (兄弟) クラスとして定義する方がユーザーにとって便利です。public親クラス内にネストされたクラスを作成することは技術的に可能publicですが、私の意見では、これを実装するのが適切なことはめったにありません。

于 2009-07-04T21:51:03.640 に答える
53

入れ子になったクラスはprivateprotectedおよび とprotected internal一緒にアクセス修飾子publicを持つことができますinternal

たとえば、オブジェクトGetEnumerator()を返すメソッドを実装しています。IEnumerator<T>消費者は、オブジェクトの実際のタイプを気にしません。彼らがそれについて知っているのは、それがそのインターフェースを実装していることだけです。返したいクラスには直接的な用途がありません。そのクラスをネストされたクラスとして宣言し、そのprivateインスタンスを返すことができます (これは実際に C# コンパイラが反復子を実装する方法です)。

class MyUselessList : IEnumerable<int> {
    // ...
    private List<int> internalList;
    private class UselessListEnumerator : IEnumerator<int> {
        private MyUselessList obj;
        public UselessListEnumerator(MyUselessList o) {
           obj = o;
        }
        private int currentIndex = -1;
        public int Current {
           get { return obj.internalList[currentIndex]; }
        }
        public bool MoveNext() { 
           return ++currentIndex < obj.internalList.Count;
        }
    }
    public IEnumerator<int> GetEnumerator() {
        return new UselessListEnumerator(this);
    }
}
于 2009-07-04T21:52:08.537 に答える
49

私が得られないのは、なぜ私がこれをする必要があるのか​​ということです

私はあなたがこれをする必要は決してないと思います。このようなネストされたクラスが与えられた...

class A
{
  //B is used to help implement A
  class B
  {
    ...etc...
  }
  ...etc...
}

...このように、いつでも内部/ネストされたクラスをグローバルスコープに移動できます...

class A
{
  ...etc...
}

//B is used to help implement A
class B
{
  ...etc...
}

ただし、BがAの実装を支援するためにのみ使用される場合、Bを内部/ネストされたクラスにすることには2つの利点があります。

  • グローバルスコープを汚染しません(たとえば、Aを見ることができるクライアントコードはBクラスが存在することさえ知らない)
  • Bのメソッドは、暗黙的にAのプライベートメンバーにアクセスできます。一方、BがA内にネストされていない場合、Aのメンバーが内部またはパブリックでない限り、BはAのメンバーにアクセスできません。ただし、これらのメンバーを内部または公開にすると、他のクラス(Bだけでなく)にも公開されます。したがって、代わりに、Aのメソッドをプライベートに保ち、Bをネストされたクラスとして宣言することにより、Bがそれらにアクセスできるようにします。C ++を知っている場合、これは、C#では、ネストされたすべてのクラスが、それらが含まれているクラスの「フレンド」であると言うようなものです(また、クラスをネストされたものとして宣言することが、C#でフレンドシップを宣言する唯一の方法です。 C#にはfriendキーワードがありません)。

BがAのプライベートメンバーにアクセスできると言うとき、それはBがAへの参照を持っていると仮定しています。ネストされたクラスはこのように宣言されることが多いため、これはよく行われます...

class A
{
  //used to help implement A
  class B
  {
    A m_a;
    internal B(A a) { m_a = a; }
    ...methods of B can access private members of the m_a instance...
  }
  ...etc...
}

...そしてこのようなコードを使用してAのメソッドから構築されます...

//create an instance of B, whose implementation can access members of self
B b = new B(this);

Mehrdadの返信で例を見ることができます。

于 2009-07-05T01:51:44.640 に答える
35

public ネストされたメンバーの有効な使用方法もあります...

ネストされたクラスは、外部クラスのプライベート メンバーにアクセスできます。したがって、これが正しい方法であるシナリオは、Comparer を作成する場合 (つまり、IComparer インターフェイスを実装する場合) です。

この例では、FirstNameComparer はプライベート _firstName メンバーにアクセスできますが、クラスが別のクラスである場合はアクセスできません...

public class Person
{
    private string _firstName;
    private string _lastName;
    private DateTime _birthday;

    //...
    
    public class FirstNameComparer : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return x._firstName.CompareTo(y._firstName);
        }
    }
}
于 2009-07-05T02:15:35.497 に答える
20

クラス内から返されるインターフェイスを実装すると便利な場合もありますが、そのインターフェイスの実装は外部から完全に隠されている必要があります。

例として、C# に yield が追加される前は、列挙子を実装する 1 つの方法は、列挙子の実装をコレクション内のプライベート クラスとして配置することでした。これにより、コレクションのメンバーに簡単にアクセスできますが、外部の世界は、これがどのように実装されているかの詳細を必要とせず、見る必要もありません。

于 2009-07-04T21:52:38.740 に答える
6

ネストされたクラスは、公開してはならない内部の詳細を実装するのに非常に役立ちます。Reflector を使用して Dictionary<Tkey,TValue> や Hashtable などのクラスをチェックすると、いくつかの例が見つかります。

于 2009-07-04T22:48:23.010 に答える
4

これは、ネストされたクラスを使用する場合の良い例でしょうか?

// ORIGINAL
class ImageCacheSettings { }
class ImageCacheEntry { }
class ImageCache
{
    ImageCacheSettings mSettings;
    List<ImageCacheEntry> mEntries;
}

と:

// REFACTORED
class ImageCache
{
    Settings mSettings;
    List<Entry> mEntries;

    class Settings {}
    class Entry {}
}

PS: どのアクセス修飾子を適用する必要があるかは考慮していません (private、protected、public、internal)

于 2011-12-31T14:36:54.627 に答える