Por que eu sempre precisaria usar classs aninhadas C #

Eu estou tentando entender sobre classs aninhadas em c #. Eu entendo que uma class aninhada é uma class que é definida dentro de outra class, o que eu não entendo é porque eu precisaria fazer isso.

   

    Um padrão que eu particularmente gosto é combinar classs aninhadas com o padrão de fábrica:

    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() { ... } } 

    Ao aninhar as classs dessa forma, impossibilito que terceiros criem suas próprias subclasss. Eu tenho controle total sobre todo o código que é executado em qualquer object de conta bancária. E todas as minhas subclasss podem compartilhar detalhes de implementação por meio da class base.

    O objective é normalmente apenas restringir o escopo da class aninhada. As classs aninhadas comparadas às classs normais têm a possibilidade adicional do modificador private (bem como protected claro).

    Basicamente, se você só precisa usar essa class dentro da class “pai” (em termos de escopo), então é geralmente apropriado defini-la como uma class aninhada. Se essa class precisar ser usada sem o assembly / library , geralmente é mais conveniente para o usuário defini-la como uma class separada (irmã), independentemente de haver ou não qualquer relacionamento conceitual entre as duas classs. Embora seja tecnicamente possível criar uma class public aninhada dentro de uma class pai public , isso é, na minha opinião, raramente uma coisa apropriada a ser implementada.

    Uma class aninhada pode ter modificadores de access protected internal private , protected e protected internal juntamente com os public e internal .

    Por exemplo, você está implementando o método GetEnumerator() que retorna um object IEnumerator . Os consumidores não se importariam com o tipo real do object. Tudo o que eles sabem é que implementa essa interface. A class que você deseja retornar não tem nenhum uso direto. Você pode declarar essa class como uma class aninhada private e retornar uma instância dela (isso é, na verdade, como o compilador C # implementa os iteradores):

     class MyUselessList : IEnumerable { // ... private List internalList; private class UselessListEnumerator : IEnumerator { 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 GetEnumerator() { return new UselessListEnumerator(this); } } 

    o que eu não entendo é porque eu precisaria fazer isso

    Eu acho que você nunca precisa fazer isso. Dada uma class aninhada como esta …

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

    … você sempre pode mover a class interna / aninhada para o escopo global, assim …

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

    No entanto, quando B é usado apenas para ajudar a implementar A, então fazer de B uma class interna / aninhada tem duas vantagens:

    • Não polui o escopo global (por exemplo, o código do cliente que pode ver A não sabe que a class B existe)
    • Os methods de B implicitamente têm access a membros privados de A; enquanto que se B não estivesse nested dentro de A, B não seria capaz de acessar membros de A a menos que esses membros fossem internos ou públicos; mas fazer esses membros internos ou públicos os expõe a outras classs também (não apenas B); então, mantenha esses methods de A privados e deixe B acessá-los declarando B como uma class aninhada. Se você conhece C ++, é como dizer que em C # todas as classs aninhadas são automaticamente ‘ amigas ‘ da class na qual elas estão contidas (e, declarar que uma class como aninhada é a única maneira de declarar amizade em C #, já que C # não tem uma palavra-chave de friend ).

    Quando digo que B pode acessar membros privados de A, supondo que B tenha uma referência a A; o que geralmente acontece, já que classs aninhadas são frequentemente declaradas assim …

     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... } 

    … e construído a partir de um método de A usando código como este …

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

    Você pode ver um exemplo na resposta de Mehrdad.

    Há bons usos de membros nesteds públicos também …

    As classs aninhadas têm access aos membros particulares da class externa. Então, um cenário em que este é o caminho certo seria ao criar um Comparer (ou seja, implementar a interface IComparer).

    Neste exemplo, o FirstNameComparer tem access ao membro _firstName privado, o que não aconteceria se a class fosse uma class separada …

     public class Person { private string _firstName; private string _lastName; private DateTime _birthday; //... public class FirstNameComparer : IComparer { public int Compare(Person x, Person y) { return x._firstName.CompareTo(y._lastName); } } } 

    Há momentos em que é útil implementar uma interface que será retornada de dentro da class, mas a implementação dessa interface deve ser completamente ocultada do mundo externo.

    Como um exemplo – antes da adição de rendimento ao C #, uma maneira de implementar enumeradores era colocar a implementação do enumerador como uma class privada dentro de uma coleção. Isso forneceria access fácil aos membros da coleção, mas o mundo externo não precisaria / veria os detalhes de como isso é implementado.

    As classs aninhadas são muito úteis para implementar detalhes internos que não devem ser expostos. Se você usar o Reflector para verificar classs como Dictionary ou Hashtable, você encontrará alguns exemplos.

    Talvez este seja um bom exemplo de quando usar classs aninhadas?

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

    E:

     // REFACTORED class ImageCache { Settings mSettings; List mEntries; class Settings {} class Entry {} } 

    PS: Não levei em consideração quais modificadores de access devem ser aplicados (privados, protegidos, públicos, internos)