Spazio dei nomi e classe con lo stesso nome?


95

Sto organizzando un progetto di libreria e ho una classe manager centrale denominata Scenegraphe un sacco di altre classi che vivono nello spazio dei nomi Scenegraph.

Quello che mi piacerebbe davvero è che lo scenegraph sia MyLib.Scenegraphe che le altre classi lo siano MyLib.Scenegraph.*, ma sembra che l'unico modo per farlo sarebbe rendere tutte le altre classi interne Scenegraphal file Scenegraph.cs e questo è semplicemente troppo ingombrante .

Invece, l'ho organizzato come Mylib.Scenegraph.Scenegraphe MyLib.Scenegraph.*, che tipo di lavoro funziona, ma trovo che Visual Studio sia confuso in alcune condizioni sul fatto che mi riferisca alla classe o allo spazio dei nomi.

C'è un buon modo per organizzare questo pacchetto in modo che sia conveniente per gli utenti senza mettere insieme tutto il mio codice in un pasticcio irrimediabile?

Risposte:


112

Non ti consiglio di nominare una classe come il suo spazio dei nomi, vedi questo .

Le Linee guida per la progettazione del framework dicono nella sezione 3.4 "non utilizzare lo stesso nome per uno spazio dei nomi e un tipo in quello spazio dei nomi". Questo è:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Perché questa cattiveria? Oh, fammi contare i modi.

Puoi metterti in situazioni in cui pensi di riferirti a una cosa, ma in realtà ti riferisci a qualcos'altro. Supponiamo di trovarvi in ​​questa sfortunata situazione: state scrivendo Blah.DLL e importando Foo.DLL e Bar.DLL, che, sfortunatamente, hanno entrambi un tipo chiamato Foo:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

Il compilatore restituisce un errore. "Foo" è ambiguo tra Foo.Foo e Bar.Foo. Bummer. Immagino che lo risolverò qualificando completamente il nome:

   class C { Foo.Foo foo; } 

Questo ora dà l'errore di ambiguità " Foo in Foo.Foo è ambiguo tra Foo.Foo e Bar.Foo ". Non sappiamo ancora a cosa si riferisce il primo Foo, e finché non riusciamo a capirlo, non ci preoccupiamo nemmeno di cercare di capire a cosa si riferisce il secondo.


6
È un punto interessante. Ci sto ancora lcogitando. Grazie. Devo essere onesto gli argomenti che iniziano con "La guida allo stile dice" non mi impressionano. Ho visto un sacco di schifezze ingiustificate nelle guide di stile. Ma fai un buon argomento pratico sopra. Vale la pena pensarci, comunque.
user430788

5
La risposta dice "cosa non fare". Mentre alcuni utenti dello stack cercano "cosa fare". Qualcuno consiglierebbe la risposta di Ant_222?
fantastory

3
Se sei davvero bloccato, puoi comunque creare un alias di tipo al di fuori del tuo spazio dei nomi. Gli alias esterni sono necessari solo quando si hanno due identificatori completi completamente identici (spazio dei nomi + nome della classe).
Geoffrey

3
Tutto quanto sopra è by-the-bye e opinione. Il fatto è che non dovresti farlo perché il compilatore C # lo fraintenderà , nonostante gli venga detto abbastanza chiaramente cosa sta succedendo. Ad esempio, in using Foo.Bar;seguito si Bar bfa chiaramente riferimento a Baruna classe (o enum) all'interno dello spazio dei nomi Foo.Bar. La vera ragione per non farlo è semplicemente che il compilatore C # non riesce a capirlo correttamente, il che è terribilmente sorprendente e sfortunato. Qualsiasi altra cosa è un consiglio di stile lanoso.
TJ Crowder

2
Non lo capisco. Perché Foo.Foo è ambiguo? Dici direttamente al compilatore che vuoi usare la classe Foo dallo spazio dei nomi Foo in questo caso specifico. No?
GuardianX

14

Dare lo stesso nome allo spazio dei nomi e alla classe può confondere il compilatore come altri hanno detto.

Come chiamarlo allora?

Se lo spazio dei nomi ha più classi, trova un nome che definisca tutte quelle classi.

Se lo spazio dei nomi ha una sola classe (e quindi la tentazione di dargli lo stesso nome) nomina lo spazio dei nomi ClassName NS . Questo è il modo in cui Microsoft nomina almeno i loro spazi dei nomi.


4
Hai un esempio di tale spazio dei nomi da Microsoft?
sunefred

Devo cercarlo e tornare da te.
Vai al

@sunefred L'ho cercato, ma non sono riuscito a trovarlo. Ma ricordo sicuramente di averlo visto nella documentazione. Immagino che non ci siano molti casi in cui si desidera avere una singola classe in uno spazio dei nomi.
GoTo

9

Ti suggerisco di seguire i consigli che ho ricevuto microsoft.public.dotnet.languages.csharpper utilizzare MyLib.ScenegraphUtil.Scenegraphe MyLib.ScenegraphUtil.*.



4

Aggiungo solo i miei 2 centesimi:

Ho seguito la seguente lezione:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

Il client è stato scritto così:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

Perdendo l'errore GetFoo che non restituisce l'output invece di utilizzare il parametro out, il compilatore non è riuscito a risolvere il tipo di dati Foo.Bar []. Stava restituendo l'errore: impossibile trovare il tipo o lo spazio dei nomi Foo.Bar.

Sembra che quando prova a compilare abbia risolto Foo come classe e non abbia trovato una barra di classe incorporata nella classe Foo. Inoltre, non è stato possibile trovare uno spazio dei nomi denominato Foo.Bar. Non è riuscito a cercare una barra di classe nello spazio dei nomi Foo. I punti in uno spazio nome NON sono sintattici. L'intera stringa è un segno, non le parole delimitate dai punti.

Questo comportamento è stato mostrato da VS 2015 con .Net 4.6


4

Anche se sono d'accordo con altre risposte in quanto non dovresti nominare la tua classe come il tuo spazio dei nomi, ci sono volte in cui non puoi soddisfare tali requisiti.

Nel mio caso, ad esempio, non ero io la persona che prendeva una tale decisione, quindi dovevo trovare un modo per farlo funzionare.

Quindi, per coloro che non possono cambiare il nome dello spazio dei nomi né il nome della classe, ecco un modo in cui puoi far funzionare il tuo codice.

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

Fondamentalmente ho creato gli "alias" dello spazio dei nomi e questo mi ha permesso di qualificare completamente la classe e la "confusione" di Visual Studio è andata via.

NOTA: dovresti evitare questo conflitto di denominazione se è sotto il tuo controllo per farlo. Dovresti usare la tecnica menzionata solo quando non hai il controllo delle classi e degli spazi dei nomi in questione.


2
L'ho votato perché era una soluzione interessante per un mondo imperfetto.
user430788

2

Vecchio post, ma qui vado con un'altra idea che potrebbe aiutare qualcuno:

"... ma sembra che l'unico modo per farlo sarebbe rendere tutte le altre classi interne di Scenegraph nel file Scenegraph.cs e questo è semplicemente troppo ingombrante."

Questa è davvero la migliore implementazione per una serie di scenari. Ma sono d'accordo che avere tutto quel codice sullo stesso file .cs è fastidioso (per non dire altro).

Puoi risolverlo rendendo la classe base una "classe parziale" e poi continuare a creare le classi interne sui propri file (ricorda solo che dovranno dichiarare il complemento della classe base e poi andare avanti con la classe interna specifica per quel file).

Qualcosa di simile a...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

Penso che questo sia il più vicino possibile ad avere l'implementazione pulita delle classi interne senza dover ingombrare tutto all'interno di un file enorme e disordinato.


2

Come altri hanno già detto, è una buona pratica evitare di nominare una classe come il suo spazio dei nomi.

Di seguito sono riportati alcuni suggerimenti di denominazione aggiuntivi da una risposta di svick a una domanda correlata "Stessa classe e nome dello spazio dei nomi" nello Stack di ingegneria del software:

Hai ragione che non dovresti nominare lo spazio dei nomi come un tipo che contiene. Penso che ci siano diversi approcci che puoi usare:

  • Pluralizza: Model.DataSources.DataSource

Funziona particolarmente bene se lo scopo principale dello spazio dei nomi è contenere tipi che ereditano dallo stesso tipo di base o implementano la stessa interfaccia.

  • Accorciare: Model.QueryStorage

Se uno spazio dei nomi contiene solo un piccolo numero di tipi, forse non è affatto necessario quello spazio dei nomi.

  • Rendi imprenditoriale: Model.ProjectSystem.Project

Questo può funzionare specialmente per le funzionalità che sono parte importante del tuo prodotto, quindi meritano il loro nome.

(Si noti che le usi risposta di cui sopra Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.e Model.Project.Projectcome esempi, piuttosto che MyLib.Scenegraph.Scenegraph.)

(Ho anche trovato utili gli altri suggerimenti di denominazione nelle altre risposte qui.)


1

Succede quando è la classe principale dello spazio dei nomi. Quindi è una motivazione mettere lo spazio dei nomi in una libreria, quindi il problema scompare se aggiungi "Lib" al nome dello spazio dei nomi ...

namespace SocketLib
{
    class Socket
    {
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.