web-dev-qa-db-fra.com

Pourquoi utiliser des classes partielles?

À ma connaissance, le mot clé partial ne fait que permettre à une classe d'être divisée entre plusieurs fichiers source. Y a-t-il une autre raison que l'organisation du code? Je l'ai vu utilisé pour cela dans les classes d'interface utilisateur générées.

Cela semble une mauvaise raison de créer un mot clé entier. Si une classe est assez grande pour nécessiter plusieurs fichiers, elle en fait probablement trop. Je pensais que vous pourriez peut-être l'utiliser pour définir partiellement une classe pour un autre programmeur quelque part, mais il serait préférable de créer une classe abstraite.

72
Michael K

Il est très utile dans chaque scénario où une partie de la classe est générée par un outil personnalisé, car elle vous permet d'ajouter une logique personnalisée au code généré sans hériter de la classe générée. Btw. il existe également des méthodes partielles pour la même raison.

Il ne s'agit pas seulement de l'interface utilisateur, mais aussi d'autres technologies comme Linq-To-Sql ou Entity Framework l'utilisent assez largement.

113
Ladislav Mrnka

Comme vous le dites, il est souvent utilisé pour séparer le code généré. Cela n'a souvent rien à voir avec la taille des classes/fichiers.

L'avantage de séparer le code généré est celui du style. Le code généré peut être assez moche et illisible et échouerait à de nombreuses normes de codage (et aux vérifications StyleCop), mais c'est OK, personne n'a à le lire ou à le maintenir directement. Donc, si vous le "cachez" dans un autre fichier, vous pouvez vous concentrer sur le fait que le reste de la classe est à la hauteur, passe les vérifications StyleCop et ainsi de suite.

Un autre domaine où je l'ai utilisé est celui où une classe implémente plusieurs interfaces, il peut être assez agréable de séparer l'implémentation dans des fichiers séparés, bien que ce soit plus une question de préférence personnelle, je n'ai jamais vu de normes de codage exiger ( ou empêcher) cela.

26
Steve

Il y a quelques semaines, l'un des développeurs où je travaille a trouvé une très bonne utilisation pour eux dans la refactorisation d'énormes classes God qui ont échappé à tout contrôle et ont beaucoup de méthodes publiques: en séparant les fonctions logiques de chaque bit de la classe en une classe partielle séparée, vous pouvez physiquement séparer la classe en unités plus atomiques qui devraient être les classes sans casser aucune fonctionnalité existante, vous permettant de voir ce qui est commun et ce qui ne l'est pas. Avec ceci comme première étape, vous pouvez ensuite séparer plus facilement les partiels en leurs propres classes indépendantes et les implémenter dans la base de code. Je pensais que c'était une bonne idée.

Cependant, en général, je pense qu'ils ne devraient être utilisés que pour augmenter les classes générées par machine lors de l'écriture de nouveau code.

19
user23157

Je peux penser à quelques scénarios utiles où les partiels ont du sens, la plupart d'entre eux que j'utilise moi-même dans mes projets:

  • Pour séparer le code généré par l'outil/IDE/Designer du code que vous gérez. Un bon exemple est le Form.Designer.cs fichier contenant le code généré par le concepteur pour les applications Windows Forms. De nombreux autres formats .NET ont également du code généré par l'outil, qui peut être potentiellement régénéré lorsque vous générez votre projet, et donc toutes vos modifications personnalisées seront balayées. La séparation vous aidera à garder votre code et vos modifications à l'abri de telles modifications automatisées.

  • Lorsque vous implémentez plusieurs interfaces avec beaucoup de code dans l'implémentation. J'ai tendance à utiliser un fichier partiel séparé pour chacune de ces interfaces, en le nommant ainsi: {Class}.{Interface}.cs. Il est facile pour moi de voir dans le IDE qui interface le {Class} met en œuvre et comment.

  • Lorsque la classe doit contenir une ou plusieurs classes imbriquées , en particulier avec suffisamment de code pour être placées dans un fichier séparé. Je m'en tiendrai au modèle ci-dessus et utiliserais le {Class}.{NestedClass}.cs convention de dénomination pour chaque classe imbriquée. Une pratique similaire est déjà mentionnée par réponse de Virtlink .

  • Quand j'écris static classes qui contiendront les méthodes d'extension . Il sera souvent le cas de fournir la même logique de méthode d'extension à des classes ou interfaces similaires - comme par exemple Reverse sur des collections génériques et non génériques. Je mettrais toutes les méthodes d'extension pour une seule classe ou interface dans un partiel séparé de la classe statique. Par exemple, j'aurais toutes les méthodes d'extension pour l'interface IList au même endroit, et les mêmes méthodes que pour IList<T> dans un autre fichier. Une autre approche serait de mettre la même méthode (toutes ses surcharges) dans le même partiel, avec toutes les classes possibles pour le paramètre this - comme avoir toutes les implémentations Reverse dans un fichier. Cela dépend de celui qui justifierait le mieux la séparation en termes de volume de code ou de certaines conventions internes auxquelles vous ou votre organisation pouvez vous en tenir.

  • Je ne l'utilise pas, mais j'ai vu des gens en C/C++ aimer l'approche que je vais décrire ici: créer un partiel pour la classe avec des méthodes partielles seulement. Cela ressemble à la façon C/C++ de définir des interfaces et de séparer la déclaration de méthode de l'implémentation.

  • Séparation par des préoccupations purement logiques . S'il vous arrive de travailler avec une grande classe qui combine plus d'un ensemble logique d'opérations en soi, vous pouvez séparer chaque code lié logiquement en un partiel distinct. Habituellement, l'existence de telles classes est contraire au principe séparation des préoccupations, mais il est souvent observé dans la réalité, en particulier pour les anciennes bases de code. Son compatriote Steve Evers les a mentionnés dans sa réponse à cette question , se référant à eux par le nom objets divins . J'utiliserais personnellement l'approche des classes partielles pour diviser le code avant toute refactorisation de fichiers vraiment volumineux, afin de faciliter mon travail et de rendre la refactorisation plus transparente. Cela réduira également les conflits que je vais potentiellement provoquer lorsque des systèmes de versioning comme SVN sont impliqués.

19
Ivaylo Slavov

Je ne l'ai vu mentionné par personne: j'utilise partial pour mettre des classes imbriquées dans leurs propres fichiers.

Tous mes fichiers de code contiennent une seule classe, struct, interface ou énumération. Il est beaucoup plus facile de trouver la définition d'un objet lorsque les noms de fichiers indiquent le nom de la chose que vous recherchez. Et puisque Visual Studio essaie de faire correspondre les dossiers de projet aux espaces de noms, les noms de fichiers doivent correspondre aux classes.

Cela signifie également qu'une classe NestedClass imbriquée dans MyClass aura son propre fichier dans mes projets: MyClass.NestedClass.cs.

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

À l'exception de l'utilisation du code généré, j'ai seulement jamais vu les utiliser dans le but de couvrir objets divins . Essayer de comprendre une nouvelle base de code ou de parcourir plusieurs fichiers source, qui sont le même objet, est tellement ennuyeux.

Donc, quand vous demandez Why use partial classes? Je réponds: sauf si vous utilisez du code généré, ne le faites pas.

10
Steven Evers

L'organisation du code est la seule raison, mais elle va plus loin qu'il n'y paraît au premier abord. Si vous avez des classes partielles où des pièces sont générées, vous pouvez facilement:

  • Régénérez le code sans avoir à détecter les modifications manuelles dans les classes dans lesquelles vous écrivez (afin de ne pas écraser ces parties).
  • Exclure les classes partielles générées de la couverture des tests, du contrôle de source, des métriques, etc.
  • Utilisez le code généré sans vous forcer à baser votre stratégie d'héritage autour de lui (vous pouvez toujours hériter d'autres classes).
6
Deckard

Je peux penser à une sale utilisation pour eux.

Supposons que certaines classes nécessitent des fonctionnalités communes, mais que vous ne souhaitez pas injecter cette fonctionnalité dans la chaîne d'héritage au-dessus d'elles. Ou, vous avez un ensemble de classes qui utilisent une classe d'assistance commune.

Fondamentalement, vous voulez faire un héritage multiple, mais pas de C #. Donc ce que vous faites est d'utiliser partial pour créer ce qui est essentiellement un #include en C/C++;

Mettez toutes les fonctionnalités dans une classe ou utilisez la classe d'assistance. Copiez ensuite l'assistant X fois et renommez-le classe partielle A, B, C. et mettez partiel sur vos classes A, B, C.

Avertissement: Oui, c'est mal. Ne le faites jamais - surtout si cela rendra les autres fâchés contre vous.

1
Mark

Il y a aussi quelques endroits où les classes générées/implicites sont déclarées partielles, donc si le développeur a besoin de les étendre, il a un accès complet sans avoir à se soucier d'hériter et de remplacer partout. Regardez les classes générées dans la zone temporaire asp.net après avoir exécuté un site webforms pour la première fois sous IIS si vous voulez essayer d'attraper quelques exemples.

1
Bill