web-dev-qa-db-fra.com

Classes internes privées en C # - pourquoi ne sont-elles pas utilisées plus souvent?

Je suis relativement nouveau en C # et chaque fois que je commence à travailler sur un projet C # (je n'ai travaillé que sur des projets presque matures en C #) je me demande pourquoi il n'y a pas de classes internes?

Peut-être que je ne comprends pas leur objectif. Pour moi, les classes internes - au moins les classes internes privées - ressemblent beaucoup à des "procédures internes" dans Pascal/Modula-2/Ada: elles permettent de décomposer une classe principale en parties plus petites afin de faciliter la compréhension.

Exemple: voici ce que l'on voit la plupart du temps:

public class ClassA
{
   public MethodA()
   {
      <some code>
      myObjectClassB.DoSomething(); // ClassB is only used by ClassA
      <some code>
   }
}

public class ClassB
{
   public DoSomething()
   {
   }
}

Étant donné que ClassB sera utilisé (au moins pendant un certain temps) uniquement par ClassA, je suppose que ce code serait mieux exprimé comme suit:

   public class ClassA
   {
      public MethodA()
      {
         <some code>
         myObjectClassB.DoSomething(); // Class B is only usable by ClassA
         <some code>
      }

      private class ClassB
      {
         public DoSomething()
         {
         }
      }
   }

Je serais heureux d'avoir de vos nouvelles à ce sujet - Ai-je raison?

74
Sylvain Rodrigue

Les classes imbriquées (probablement mieux pour éviter le mot "interne" car les classes imbriquées en C # sont quelque peu différentes des classes internes en Java) peuvent en effet être très utiles.

Un modèle qui n'a pas été mentionné est le modèle "meilleure énumération" - qui peut être encore plus flexible que celui de Java:

public abstract class MyCleverEnum
{
    public static readonly MyCleverEnum First = new FirstCleverEnum();
    public static readonly MyCleverEnum Second = new SecondCleverEnum();

    // Can only be called by this type *and nested types*
    private MyCleverEnum()
    {
    }

    public abstract void SomeMethod();
    public abstract void AnotherMethod();

    private class FirstCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // First-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // First-specific behaviour here
        }
    }

    private class SecondCleverEnum : MyCleverEnum
    {
        public override void SomeMethod()
        {
             // Second-specific behaviour here
        }

        public override void AnotherMethod()
        {
             // Second-specific behaviour here
        }
    }
}

Nous pourrions faire avec une certaine prise en charge de la langue pour le faire automatiquement - et il y a beaucoup d'options que je n'ai pas montré ici, comme ne pas utiliser réellement une classe imbriquée pour toutes les valeurs, ou utiliser la même classe imbriquée pour plusieurs valeurs, mais en leur donnant différents paramètres de constructeur. Mais fondamentalement, le fait que la classe imbriquée puisse appeler le constructeur privé donne beaucoup de pouvoir.

77
Jon Skeet

Le Framework Design Guidelines a les meilleures règles d'utilisation des classes imbriquées que j'ai trouvées à ce jour.

Voici une brève liste récapitulative:

  1. Utilisez des types imbriqués lorsque la relation entre le type et le type imbriqué est telle que la sémantique d'accessibilité aux membres est souhaitée.

  2. N'utilisez pas [~ # ~] [~ # ~] les types publics imbriqués comme construction de groupe logique

  3. Évitez d'utiliser des types imbriqués exposés publiquement.

  4. N'utilisez pas [~ # ~] et [~ # ~] les types imbriqués si le type est susceptible d'être référencé en dehors du type conteneur.

  5. N'utilisez pas [~ # ~] et [~ # ~] les types imbriqués s'ils doivent être instanciés par le code client.

  6. Ne [~ # ~] pas [~ # ~] définissez un type imbriqué en tant que membre d'une interface.

29
matt_dev

Vous devez limiter les responsabilités de chaque classe afin que chacune reste simple, testable et réutilisable. Les classes intérieures privées vont à l'encontre de cela. Ils contribuent à la complexité de la classe externe, ils ne sont pas testables et ils ne sont pas réutilisables.

12
Wim Coenen

Pour moi personnellement, je ne crée des classes internes privées que si j'ai besoin de créer des collections en cours d'un objet qui peuvent nécessiter des méthodes sur elles.

Sinon, cela pourrait créer de la confusion pour les autres développeurs travaillant sur le projet pour trouver réellement ces classes, car ils ne sont pas très clairs quant à leur emplacement.

3
Tom Anderson