c# Le direttive "using" dovrebbero essere all'interno o all'esterno dello spazio dei nomi?





5 Answers

Questa discussione ha già delle ottime risposte, ma sento di poter dare un po 'più di dettaglio con questa risposta aggiuntiva.

Innanzitutto, ricorda che una dichiarazione dello spazio dei nomi con punti, come:

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

è interamente equivalente a:

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

Se lo volessi, potresti using direttive su tutti questi livelli. (Ovviamente, vogliamo using s in un solo posto, ma sarebbe legale secondo la lingua.)

La regola per la risoluzione di quale tipo è implicito, può essere definita in modo approssimativo come segue: Prima cerca lo "scope" più interno per una corrispondenza, se non viene trovato nulla, esci di un livello nello scope successivo e cerca lì, e così via , fino a quando non viene trovata una corrispondenza. Se a un certo livello viene trovata più di una corrispondenza, se uno dei tipi proviene dall'assieme corrente, sceglierne uno ed emettere un avviso del compilatore. Altrimenti, arrendersi (errore in fase di compilazione).

Ora, diciamo esplicitamente cosa significa questo in un esempio concreto con le due principali convenzioni.

(1) Con gli usi esterni:

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

Nel caso precedente, per scoprire che tipo è Ambiguous , la ricerca va in questo ordine:

  1. Tipi annidati all'interno di C (inclusi tipi annidati ereditati)
  2. Tipi nello spazio dei nomi corrente MyCorp.TheProduct.SomeModule.Utilities
  3. Tipi nello spazio MyCorp.TheProduct.SomeModule nomi MyCorp.TheProduct.SomeModule
  4. Tipi in MyCorp.TheProduct
  5. Tipi in MyCorp
  6. Tipi nello spazio dei nomi null (lo spazio dei nomi globale)
  7. Tipi in System , System.Collections.Generic , System.Linq , MyCorp.TheProduct.OtherModule , MyCorp.TheProduct.OtherModule.Integration e ThirdParty

L'altra convenzione:

(2) Con le usanze all'interno:

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

Ora, cerca il tipo Ambiguous in questo ordine:

  1. Tipi annidati all'interno di C (inclusi tipi annidati ereditati)
  2. Tipi nello spazio dei nomi corrente MyCorp.TheProduct.SomeModule.Utilities
  3. Tipi in System , System.Collections.Generic , System.Linq , MyCorp.TheProduct , MyCorp.TheProduct.OtherModule , MyCorp.TheProduct.OtherModule.Integration e ThirdParty
  4. Tipi nello spazio MyCorp.TheProduct.SomeModule nomi MyCorp.TheProduct.SomeModule
  5. Tipi in MyCorp
  6. Tipi nello spazio dei nomi null (lo spazio dei nomi globale)

(Si noti che MyCorp.TheProduct faceva parte di "3." e non era quindi necessario tra "4." e "5.".)

Osservazioni conclusive

Non importa se si inseriscono gli usi all'interno o all'esterno della dichiarazione dello spazio dei nomi, c'è sempre la possibilità che qualcuno aggiunga successivamente un nuovo tipo con un nome identico a uno degli spazi dei nomi che hanno una priorità più alta.

Inoltre, se uno spazio dei nomi annidato ha lo stesso nome di un tipo, può causare problemi.

È sempre pericoloso spostare gli usi da una posizione a un'altra perché la gerarchia della ricerca cambia e un altro tipo può essere trovato. Pertanto, scegli una convenzione e atteniti ad essa, in modo da non dover mai spostare gli usi.

I modelli di Visual Studio, per impostazione predefinita, inseriscono gli utilizzi al di fuori dello spazio dei nomi (ad esempio se si crea VS in una nuova classe in un nuovo file).

Un (piccolo) vantaggio di avere usi esterni è che è quindi possibile utilizzare le direttive using per un attributo globale, ad esempio [assembly: ComVisible(false)] invece di [assembly: System.Runtime.InteropServices.ComVisible(false)] .

c# .net namespaces stylecop code-organization

Ho eseguito StyleCop su un codice C # e continua a segnalare che le mie direttive di using dovrebbero essere all'interno dello spazio dei nomi.

Esiste un motivo tecnico per inserire le direttive di using all'interno anziché all'esterno dello spazio dei nomi?







C'è un problema con l'inserimento di istruzioni all'interno dello spazio dei nomi quando si desidera utilizzare alias. L'alias non beneficia delle dichiarazioni precedenti e deve essere pienamente qualificato.

Tenere conto:

namespace MyNamespace
{
    using System;
    using MyAlias = System.DateTime;

    class MyClass
    {
    }
}

contro:

using System;

namespace MyNamespace
{
    using MyAlias = DateTime;

    class MyClass
    {
    }
}

Questo può essere particolarmente pronunciato se si ha un alias prolisso come il seguente (che è il modo in cui ho trovato il problema):

using MyAlias = Tuple<Expression<Func<DateTime, object>>, Expression<Func<TimeSpan, object>>>;

Con l' using istruzioni all'interno dello spazio dei nomi, diventa improvvisamente:

using MyAlias = System.Tuple<System.Linq.Expressions.Expression<System.Func<System.DateTime, object>>, System.Linq.Expressions.Expression<System.Func<System.TimeSpan, object>>>;

Non carino.




Un'altra sottigliezza che non credo sia stata coperta dalle altre risposte è per quando hai una classe e un namespace con lo stesso nome.

Quando hai l'importazione all'interno dello spazio dei nomi, troverà la classe. Se l'importazione è al di fuori dello spazio dei nomi, l'importazione verrà ignorata e la classe e lo spazio dei nomi devono essere pienamente qualificati.

//file1.cs
namespace Foo
{
    class Foo
    {
    }
}

//file2.cs
namespace ConsoleApp3
{
    using Foo;
    class Program
    {
        static void Main(string[] args)
        {
            //This will allow you to use the class
            Foo test = new Foo();
        }
    }
}

//file2.cs
using Foo; //Unused and redundant    
namespace Bar
{
    class Bar
    {
        Bar()
        {
            Foo.Foo test = new Foo.Foo();
            Foo test = new Foo(); //will give you an error that a namespace is being used like a class.
        }
    }
}



È una pratica migliore se quelle impostazioni predefinite che utilizzano, ad esempio, i " riferimenti " utilizzati nella soluzione di origine, dovrebbero essere al di fuori degli spazi dei nomi e quelli che sono "nuovi riferimenti aggiunti" è una buona pratica, dovresti inserirli nello spazio dei nomi. Questo per distinguere quali riferimenti vengono aggiunti.




Related