2350 votes

Devraient à l'aide de l'état à l'intérieur ou à l'extérieur de l'espace de noms?

J'ai été en cours d'exécution StyleCop sur un code C# et il continue à annoncer que mon utilisation d'instructions doit être à l'intérieur de l'espace de noms.

Est-il une raison technique pour mettre les instructions à l'aide à l'intérieur au lieu de l'extérieur de l'espace de noms?

2355voto

Charlie Points 17807

Il est en fait un (subtile) de différence entre les deux. Imaginez que vous avez le code suivant dans le fichier Fichier1.cs:

// File1.cs
using System;
namespace Outer.Inner
{
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Maintenant, imaginez que quelqu'un ajoute un autre fichier (Fichier2.cs) pour le projet qui ressemble à ceci:

// File2.cs
namespace Outer
{
    class Math
    {
    }
}

Le compilateur cherche Outer avant de regarder ceux - using des déclarations en dehors de l'espace de noms, de sorte qu'il détecte Outer.Math au lieu de System.Math. Malheureusement (ou heureusement?), Outer.Math n'a pas d' PI membre, si Fichier1 est aujourd'hui brisé.

Cela change si vous mettez l' using à l'intérieur de votre déclaration d'espace de noms, comme suit:

// File1b.cs
namespace Outer.Inner
{
    using System;
    class Foo
    {
        static void Bar()
        {
            double d = Math.PI;
        }
    }
}

Maintenant, le compilateur cherche System avant de chercher Outer, conclut System.Math, et tout est bien.

Certains diront que l' Math pourrait être un mauvais nom pour une classe définie par l'utilisateur, puisqu'il y a déjà une en System; le point ici est juste qu'il y est une différence, et elle affecte la maintenabilité du code.

Il est également intéressant de noter ce qui se passe si Foo est dans l'espace de noms Outer, plutôt que d' Outer.Inner. Dans ce cas, l'ajout d' Outer.Math dans Fichier2 pauses Fichier1 indépendamment de l'endroit où l' using va. Cela implique que le compilateur cherche à l'enfermer les plus secrets de l'espace de noms avant qu'il ressemble à l' using des déclarations.

555voto

Jeppe Stig Nielsen Points 17887

Ce thread a déjà de grandes réponses, mais je sens que je peux apporter un peu plus en détail de cette réponse supplémentaire.

Tout d'abord, rappelez-vous qu'une déclaration d'espace de noms avec des périodes, comme:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    ...
}

est totalement équivalente à:

namespace MyCorp
{
    namespace TheProduct
    {
        namespace SomeModule
        {
            namespace Utilities
            {
                ...
            }
        }
    }
}

Si vous vouliez, vous pourriez mettre using directives sur l'ensemble de ces niveaux. (Bien sûr, nous voulons usings dans un seul endroit, mais il serait possible de le faire en fonction de la langue.)

La règle de résolution qui est de type implicite, peut-être vaguement indiqué comme ceci: d'Abord la recherche à l'intérieur de la plupart des "portée" pour un match, si rien n'est trouvé là, vous passez d'un niveau à la prochaine portée et de la recherche, et ainsi de suite, jusqu'à ce qu'une correspondance soit trouvée. Si, à un niveau plus qu'une correspondance est trouvée, si l'un de ces types sont de l'actuelle assemblée, choisir que l'un et émettre un avertissement du compilateur. Sinon, abandonner (erreur de compilation).

Maintenant, soyons clair sur ce que cela signifie dans un exemple concret avec les deux grandes conventions.

(1) Avec l'usage à l'extérieur:

using System;
using System.Collections.Generic;
using System.Linq;
//using MyCorp.TheProduct;  <-- uncommenting this would change nothing
using MyCorp.TheProduct.OtherModule;
using MyCorp.TheProduct.OtherModule.Integration;
using ThirdParty;

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    class C
    {
        Ambiguous a;
    }
}

Dans le cas ci-dessus, à savoir quel type Ambiguous est, la recherche va dans cet ordre:

  1. Les types imbriqués à l'intérieur d' C (y compris hérité les types imbriqués)
  2. Types dans l'espace de noms courant MyCorp.TheProduct.SomeModule.Utilities
  3. Types dans l'espace de noms MyCorp.TheProduct.SomeModule
  4. Types en MyCorp.TheProduct
  5. Types en MyCorp
  6. Les Types de l' null espace de noms (namespace global)
  7. Types en System, System.Collections.Generic, System.Linq, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, et ThirdParty

L'autre convention:

(2) Avec l'usage à l'intérieur:

namespace MyCorp.TheProduct.SomeModule.Utilities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using MyCorp.TheProduct;                           // MyCorp can be left out; this using is NOT redundant
    using MyCorp.TheProduct.OtherModule;               // MyCorp.TheProduct can be left out
    using MyCorp.TheProduct.OtherModule.Integration;   // MyCorp.TheProduct can be left out
    using ThirdParty;

    class C
    {
        Ambiguous a;
    }
}

Désormais, la recherche pour le type Ambiguous va dans cet ordre:

  1. Les types imbriqués à l'intérieur d' C (y compris hérité les types imbriqués)
  2. Types dans l'espace de noms courant MyCorp.TheProduct.SomeModule.Utilities
  3. Types en System, System.Collections.Generic, System.Linq, MyCorp.TheProduct, MyCorp.TheProduct.OtherModule, MyCorp.TheProduct.OtherModule.Integration, et ThirdParty
  4. Types dans l'espace de noms MyCorp.TheProduct.SomeModule
  5. Types en MyCorp
  6. Les Types de l' null espace de noms (namespace global)

(À noter qu' MyCorp.TheProduct a été une partie de "3" et n'a donc pas besoin, entre les "4." "5.".)

Remarques finales

Peu importe si vous mettez l'usage à l'intérieur ou à l'extérieur de la déclaration d'espace de noms, il y a toujours la possibilité que quelqu'un, plus tard, ajoute un nouveau type avec un nom identique à l'un des espaces de noms qui sont prioritaires.

Aussi, si un espace de noms imbriqué a le même nom qu'un type, il peut causer des problèmes.

Il est toujours dangereux de déplacer l'usage d'un endroit à l'autre à la recherche de modifications de la hiérarchie, et d'un autre type peut être trouvé. Par conséquent, choisir une convention et s'y tenir, de sorte que vous n'aurez pas à déplacer jamais l'usage.

Visual Studio modèles, par défaut, mettez l'usage à 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 l'usage à l'extérieur , c'est que vous pouvez alors utiliser l'aide de directives pour un attribut global, par exemple [assembly: ComVisible(false)] au lieu de [assembly: System.Runtime.InteropServices.ComVisible(false)].

210voto

Mark Cidade Points 53945

Mettre à l'intérieur des espaces de fait les déclarations locales de l'espace de nom pour le fichier (dans le cas où vous avez plusieurs espaces de noms dans le fichier), mais si vous avez seulement un espace de noms par fichier puis ça ne fait pas de différence si ils vont à l'extérieur ou à l'intérieur de l'espace de noms.

using ThisNamespace.IsImported.InAllNamespaces.Here;

namespace Namespace1
{ 
   using ThisNamespace.IsImported.InNamespace1.AndNamespace2;

   namespace Namespace2
   { 
      using ThisNamespace.IsImported.InJustNamespace2;
   }       
}

namespace Namespace3
{ 
   using ThisNamespace.IsImported.InJustNamespace3;
}

64voto

Quintin Robinson Points 41988

Selon , Hanselman - à l'Aide de la Directive et de l'Assemblée de Chargement... et d'autres articles il n'y a techniquement aucune différence.

Ma préférence est pour les mettre à l'extérieur des espaces de noms.

59voto

JaredCacurak Points 470

Selon le StyleCop de la Documentation:

SA1200: UsingDirectivesMustBePlacedWithinnamespace

Cause A C# à l'aide de la directive est placé à l'extérieur d'un espace de noms de l'élément.

Description De La Règle Une violation de cette règle se produit lorsqu'une directive using ou une aide-directive alias est placé à l'extérieur d'un espace de noms de l'élément, à moins que le fichier ne contient pas tous les éléments d'espace de noms.

Par exemple, le code suivant devrait aboutir à deux violations de cette règle.

using System;
using Guid = System.Guid;

namespace Microsoft.Sample
{
    public class Program
    {
    }
}

Le code suivant, cependant, ne serait pas le résultat de violations de cette règle:

namespace Microsoft.Sample
{
    using System;
    using Guid = System.Guid;

    public class Program
    {
    }
}

Ce code compile correctement, sans aucune erreurs du compilateur. Cependant, il est difficile de savoir quelle version du type de Guid est en cours d'attribution. Si l'aide de la directive est déplacé à l'intérieur de l'espace de noms, comme indiqué ci-dessous, une erreur de compilation se produit:

namespace Microsoft.Sample
{
    using Guid = System.Guid;
    public class Guid
    {
        public Guid(string s)
        {
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            Guid g = new Guid("hello");
        }
    }
}

Le code ne fonctionne pas sur l'erreur de compilation suivant, trouvé sur la ligne contenant Guid g = new Guid("hello");

CS0576: espace de Noms 'Microsoft.L'échantillon contient une définition en conflit avec alias "Guid"

Le code crée un alias pour le Système.Guid type appelé Guid, et crée également son propre type appelé Guid avec un constructeur d'interface. 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 l'aide-directive alias est placé à l'extérieur de l'espace de noms de l'élément, le compilateur va choisir la définition locale de Guid définie dans l'espace de noms local, et d'ignorer complètement l'aide-directive alias définis en dehors de l'espace de noms. Cela, malheureusement, n'est pas évidente lors de la lecture du code.

Lorsque l'aide-directive alias est positionné à l'intérieur de l'espace de noms, cependant, le compilateur a le choix entre deux différents, contradictoires Guid types à la fois au sein du même espace de noms. Ces deux types de fournir une correspondance constructeur. Le compilateur est incapable de prendre une décision, alors il signale l'erreur du compilateur.

Placer l'alias de la directive à l'extérieur de l'espace de noms est une mauvaise pratique car elle peut conduire à des confusions dans les situations de ce type, où il n'est pas évident version du type qui est réellement utilisé. Cela peut potentiellement conduire à un bogue qui pourrait être difficile à diagnostiquer.

En plaçant l'aide-alias directives au sein de l'espace de noms de l'élément élimine une source de bugs.

  1. Plusieurs Espaces De Noms

Placer plusieurs éléments d'espace de noms dans un fichier unique est généralement une mauvaise idée, mais si et quand cela est fait, c'est une bonne idée de placer tous en utilisant les directives au sein de chacun des éléments d'espace de noms, plutôt que globalement en haut du fichier. Ce sera portée des espaces de bien, et permettra également d'éviter le genre de comportement décrit ci-dessus.

Il est important de noter que lorsque le code a été écrit avec l'aide de directives placées à l'extérieur de l'espace de noms, les soins doivent être prises lors du déplacement de ces directives au sein de l'espace de noms, pour s'assurer que cela ne change pas la sémantique du code. Comme expliqué ci-dessus, en plaçant l'aide-alias directives au sein de l'espace de noms de l'élément permet au compilateur de choisir entre des types, de manière à ne pas se produire lorsque les directives sont placés à l'extérieur de l'espace de noms.

Comment faire pour Résoudre les Violations Pour corriger une violation de cette règle, toutes les déplacer à l'aide de directives et de l'aide-alias directives au sein de l'espace de noms de l'élément.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X