J'ai exécuté StyleCop sur du code C #, et il continue de signaler que mes using
directives devraient être à l'intérieur de l'espace de noms.
Y a-t-il une raison technique pour placer les using
directives à l'intérieur plutôt qu'à l'extérieur de l'espace de noms?
c#
.net
namespaces
stylecop
code-organization
benPearce
la source
la source
using
déclarations ; ce sont desusing
directives . Uneusing
instruction, d'autre part, est une structure de langage qui se produit avec d'autres instructions à l'intérieur d'un corps de méthode, etc. À titre d'exemple,using (var e = s.GetEnumerator()) { /* ... */ }
est une instruction qui est à peu près la même quevar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
déclarations dans lesnamespace
déclarations, dans leurs lignes directrices de codage internesRéponses:
Il y a en fait une différence (subtile) entre les deux. Imaginez que vous ayez le code suivant dans File1.cs:
Imaginez maintenant que quelqu'un ajoute un autre fichier (File2.cs) au projet qui ressemble à ceci:
Le compilateur recherche
Outer
avant de regarder cesusing
directives en dehors de l'espace de noms, donc il les trouve à laOuter.Math
place deSystem.Math
. Malheureusement (ou peut-être heureusement?), N'aOuter.Math
aucunPI
membre, donc File1 est maintenant cassé.Cela change si vous placez l'
using
intérieur de votre déclaration d'espace de noms, comme suit:Maintenant, le compilateur recherche
System
avant de chercherOuter
, trouveSystem.Math
et tout va bien.Certains diront que cela
Math
pourrait être un mauvais nom pour une classe définie par l'utilisateur, car il y en a déjà unSystem
; le point ici est juste qu'il y a une différence, et elle affecte la maintenabilité de votre code.Il est également intéressant de noter ce qui se passe si
Foo
est dans l'espace de nomsOuter
plutôt queOuter.Inner
. Dans ce cas, l'ajoutOuter.Math
de File2 interrompt File1, peu importe où celausing
va. Cela implique que le compilateur recherche l'espace de noms englobant le plus intérieur avant d'examiner touteusing
directive.la source
Ce fil a déjà d'excellentes réponses, mais je pense que je peux apporter un peu plus de détails avec cette réponse supplémentaire.
Tout d'abord, rappelez-vous qu'une déclaration d'espace de noms avec des points, comme:
est entièrement équivalent à:
Si vous le vouliez, vous pourriez mettre des
using
directives à tous ces niveaux. (Bien sûr, nous voulons avoir desusing
s dans un seul endroit, mais ce serait légal selon la langue.)La règle de résolution du type implicite peut être énoncée de la manière suivante: commencez par rechercher la "portée" la plus interne pour une correspondance, si rien n'y est trouvé, sortez d'un niveau à la portée suivante et recherchez-y, et ainsi de suite , jusqu'à ce qu'une correspondance soit trouvée. Si, à un certain niveau, plusieurs correspondances sont trouvées, si l'un des types provient de l'assembly actuel, sélectionnez-le et émettez un avertissement du compilateur. Sinon, abandonnez (erreur de compilation).
Maintenant, soyons explicites sur ce que cela signifie dans un exemple concret avec les deux principales conventions.
(1) Avec des utilisations à l'extérieur:
Dans le cas ci-dessus, pour savoir de quel type il
Ambiguous
s'agit, la recherche se déroule dans cet ordre:C
(y compris les types imbriqués hérités)MyCorp.TheProduct.SomeModule.Utilities
MyCorp.TheProduct.SomeModule
MyCorp.TheProduct
MyCorp
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
etThirdParty
L'autre convention:
(2) Avec des utilisations à l'intérieur:
Maintenant, recherchez le type
Ambiguous
dans cet ordre:C
(y compris les types imbriqués hérités)MyCorp.TheProduct.SomeModule.Utilities
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
etThirdParty
MyCorp.TheProduct.SomeModule
MyCorp
(Notez que cela
MyCorp.TheProduct
faisait partie de "3." et n'était donc pas nécessaire entre "4." et "5.".)Remarques finales
Peu importe si vous placez les utilisations à l'intérieur ou à l'extérieur de la déclaration d'espace de noms, il est toujours possible que quelqu'un ajoute plus tard un nouveau type avec un nom identique à l'un des espaces de noms qui ont une priorité plus élevée.
En outre, si un espace de noms imbriqué a le même nom qu'un type, il peut provoquer des problèmes.
Il est toujours dangereux de déplacer les utilisations d'un emplacement à un autre car la hiérarchie de recherche change et un autre type peut être trouvé. Par conséquent, choisissez une convention et respectez-la, de sorte que vous n'aurez jamais à déplacer les utilisations.
Les modèles de Visual Studio, par défaut, mettent les utilisations à l' extérieur de l'espace de noms (par exemple si vous faites VS générer une nouvelle classe dans un nouveau fichier).
Un (petit) avantage d'avoir des utilisations à l' extérieur est que vous pouvez ensuite utiliser les directives using pour un attribut global, par exemple
[assembly: ComVisible(false)]
au lieu de[assembly: System.Runtime.InteropServices.ComVisible(false)]
.la source
Le placer à l'intérieur des espaces de noms rend les déclarations locales à cet espace de noms pour le fichier (dans le cas où vous avez plusieurs espaces de noms dans le fichier) mais si vous n'avez qu'un seul espace de noms par fichier, cela ne fait pas beaucoup de différence, qu'ils sortent ou à l'intérieur de l'espace de noms.
la source
using
les directives dans lesnamespace
blocs peuvent faire référence à des espaces de noms relatifs basés sur lenamespace
bloc englobant .Selon Hanselman - Utilisation de la directive et du chargement d'assemblage ... et d'autres articles de ce type, il n'y a techniquement aucune différence.
Ma préférence est de les mettre en dehors des espaces de noms.
la source
My style is to put them outside the namespaces.
- à peine une réponse du tout.Selon la documentation StyleCop:
SA1200: Utilisation de DirectivesMustBePlacedWithinNamespace
Cause La directive using AC # est placée en dehors d'un élément d'espace de noms.
Description de la règle Une violation de cette règle se produit lorsqu'une directive using ou une directive using-alias est placée en dehors d'un élément d'espace de noms, sauf si le fichier ne contient aucun élément d'espace de noms.
Par exemple, le code suivant entraînerait deux violations de cette règle.
Le code suivant, cependant, n'entraînerait aucune violation de cette règle:
Ce code se compilera proprement, sans aucune erreur de compilation. Cependant, il n'est pas clair quelle version du type Guid est allouée. Si la directive using est déplacée à l'intérieur de l'espace de noms, comme illustré ci-dessous, une erreur de compilation se produira:
Le code échoue sur l'erreur de compilation suivante, trouvée sur la ligne contenant
Guid g = new Guid("hello");
CS0576: l'espace de noms «Microsoft.Sample» contient une définition en conflit avec l'alias «Guid»
Le code crée un alias pour le type System.Guid appelé Guid et crée également son propre type appelé Guid avec une interface de constructeur correspondante. Plus tard, le code crée une instance du type Guid. Pour créer cette instance, le compilateur doit choisir entre les deux définitions différentes de Guid. Lorsque la directive using-alias est placée en dehors de l'élément namespace, le compilateur choisit la définition locale de Guid définie dans l'espace de noms local et ignore complètement la directive using-alias définie en dehors de l'espace de noms. Ce n'est malheureusement pas évident lors de la lecture du code.
Cependant, lorsque la directive using-alias est positionnée dans l'espace de noms, le compilateur doit choisir entre deux types de Guid différents et conflictuels définis dans le même espace de noms. Ces deux types fournissent un constructeur correspondant. Le compilateur n'est pas en mesure de prendre une décision, il signale donc l'erreur du compilateur.
Placer la directive using-alias en dehors de l'espace de noms est une mauvaise pratique car cela peut entraîner de la confusion dans des situations comme celle-ci, où il n'est pas évident de savoir quelle version du type est réellement utilisée. Cela peut potentiellement conduire à un bug qui pourrait être difficile à diagnostiquer.
Le fait de placer des directives using-alias dans l'élément namespace élimine cela comme source de bogues.
Placer plusieurs éléments d'espace de noms dans un seul fichier est généralement une mauvaise idée, mais si et quand cela est fait, c'est une bonne idée de placer toutes les directives d'utilisation dans chacun des éléments d'espace de noms, plutôt que globalement en haut du fichier. Cela limitera étroitement les espaces de noms et aidera également à éviter le type de comportement décrit ci-dessus.
Il est important de noter que lorsque le code a été écrit en utilisant des directives placées en dehors de l'espace de noms, il faut faire attention lors du déplacement de ces directives dans l'espace de noms, pour s'assurer que cela ne change pas la sémantique du code. Comme expliqué ci-dessus, le placement de directives using-alias dans l'élément namespace permet au compilateur de choisir entre des types en conflit d'une manière qui ne se produira pas lorsque les directives seront placées en dehors de l'espace de noms.
Comment corriger les violations Pour corriger une violation de cette règle, déplacez toutes les directives using et les directives using-alias dans l'élément namespace.
la source
using
s en dehors de l'espace de noms. Innerusing
me semble si moche. :)Il y a un problème avec le placement d'instructions using dans l'espace de noms lorsque vous souhaitez utiliser des alias. L'alias ne bénéficie pas des
using
déclarations précédentes et doit être pleinement qualifié.Considérer:
contre:
Cela peut être particulièrement prononcé si vous avez un alias de longue haleine tel que le suivant (c'est ainsi que j'ai trouvé le problème):
Avec des
using
instructions à l'intérieur de l'espace de noms, cela devient soudain:Pas beau.
la source
class
besoin d'un nom (identifiant). Vous ne pouvez pas avoir deusing
directive à l'intérieur d'une classe comme vous l'indiquez. Il doit être au niveau de l'espace de noms, par exemple en dehors de l'extérieurnamespace
, ou juste à l'intérieur de l'intérieurnamespace
(mais pas à l'intérieur d'une classe / interface / etc.).using
directives par erreur. Je l'ai édité comme je le souhaitais. Merci d'avoir souligné. Le raisonnement est toujours le même, cependant.Comme Jeppe Nielsen Stig dit , ce fil a déjà de grandes réponses, mais je pensais que cette subtilité assez évidente était utile de mentionner aussi.
using
Les directives spécifiées à l'intérieur des espaces de noms peuvent rendre le code plus court car elles n'ont pas besoin d'être pleinement qualifiées comme lorsqu'elles sont spécifiées à l'extérieur.L'exemple suivant fonctionne parce que les types
Foo
etBar
sont à la fois dans le même espace de noms global,Outer
.Supposons que le fichier de code Foo.cs :
Et Bar.cs :
Cela peut omettre l'espace de noms externe dans la
using
directive, pour faire court:la source
Une ride que j'ai rencontrée (qui n'est pas couverte dans d'autres réponses):
Supposons que vous ayez ces espaces de noms:
Lorsque vous utilisez
using Something.Other
dehors d'unnamespace Parent
, il se réfère au premier (Quelque chose.Autre).Cependant, si vous l'utilisez dans cette déclaration d'espace de noms, elle se réfère à la seconde (Parent.Something.Other)!
Il existe une solution simple: ajoutez le
global::
préfixe " ": docsla source
Les raisons techniques sont discutées dans les réponses et je pense qu'en fin de compte, il s'agit des préférences personnelles, car la différence n'est pas si grande et il y a des compromis pour les deux. Le modèle par défaut de Visual Studio pour créer des
.cs
fichiers utilise desusing
directives en dehors des espaces de noms, par exempleOn peut ajuster stylecop pour vérifier les
using
directives en dehors des espaces de noms en ajoutant unstylecop.json
fichier à la racine du fichier de projet avec ce qui suit:Vous pouvez créer ce fichier de configuration au niveau de la solution et l'ajouter à vos projets en tant que «fichier de lien existant» pour partager également la configuration entre tous vos projets.
la source
Une autre subtilité que je ne pense pas avoir été couverte par les autres réponses est quand vous avez une classe et un espace de noms avec le même nom.
Lorsque vous avez l'importation à l'intérieur de l'espace de noms, il trouvera la classe. Si l'importation est en dehors de l'espace de noms, l'importation sera ignorée et la classe et l'espace de noms doivent être pleinement qualifiés.
la source
C'est une meilleure pratique si ceux qui utilisent par défaut les « références » utilisées dans votre solution source doivent être en dehors des espaces de noms et ceux qui sont de «nouvelles références ajoutées» est une bonne pratique si vous devez les mettre à l'intérieur de l'espace de noms. C'est pour distinguer quelles références sont ajoutées.
la source