Namespace und gleichnamige Klasse?

95

Ich organisiere ein Bibliotheksprojekt und habe eine zentrale Manager-Klasse mit dem Namen Scenegraphund eine ganze Reihe anderer Klassen, die im Scenegraph-Namespace leben.

Was ich wirklich möchte, ist, dass der Szenegraph MyLib.Scenegraphund die anderen Klassen sind MyLib.Scenegraph.*, aber es scheint die einzige Möglichkeit zu sein, alle anderen Klassen zu inneren Klassen Scenegraphin der Datei Scenegraph.cs zu machen, und das ist einfach zu unhandlich .

Stattdessen habe ich es als Mylib.Scenegraph.Scenegraphund organisiert MyLib.Scenegraph.*, welche Art von Arbeit, aber ich finde, dass Visual Studio unter bestimmten Bedingungen verwirrt ist, ob ich mich auf die Klasse oder den Namespace beziehe.

Gibt es eine gute Möglichkeit, dieses Paket so zu organisieren, dass es für Benutzer bequem ist, ohne meinen gesamten Code in einem nicht zu wartenden Durcheinander zusammenzufassen?

user430788
quelle

Antworten:

112

Ich empfehle Ihnen nicht eine Klasse wie sein Namensraum zu nennen, finden Sie diese .

In den Framework Design Guidelines heißt es in Abschnitt 3.4: „Verwenden Sie nicht denselben Namen für einen Namespace und einen Typ in diesem Namespace.“ Das ist:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Warum ist das schlecht? Oh, lass mich die Wege zählen.

Sie können sich in Situationen bringen, in denen Sie denken, Sie beziehen sich auf eine Sache, aber tatsächlich auf etwas anderes. Angenommen, Sie geraten in diese unglückliche Situation: Sie schreiben Blah.DLL und importieren Foo.DLL und Bar.DLL, die leider beide einen Typ namens Foo haben:

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

Der Compiler gibt einen Fehler aus. "Foo" ist zwischen Foo.Foo und Bar.Foo nicht eindeutig. Schade. Ich denke, ich werde das beheben, indem ich den Namen vollständig qualifiziere:

   class C { Foo.Foo foo; } 

Dies gibt nun den Mehrdeutigkeitsfehler " Foo in Foo.Foo ist zwischen Foo.Foo und Bar.Foo mehrdeutig ". Wir wissen immer noch nicht, worauf sich das erste Foo bezieht, und bis wir das herausfinden können, versuchen wir nicht einmal herauszufinden, worauf sich das zweite bezieht.

Pinckerman
quelle
6
Es ist ein interessanter Punkt. Ich denke immer noch darüber nach. Vielen Dank. Ich muss ehrliche Argumente sein, die mit "Der Styleguide sagt" beginnen, beeindrucken mich nicht. Ich habe eine Menge ungerechtfertigten Mist in Styleguides gesehen. Aber Sie machen oben ein gutes praktisches Argument. Es lohnt sich jedenfalls darüber nachzudenken.
user430788
5
Die Antwort sagt "was nicht zu tun ist". Während einige Stapelbenutzer nach "was zu tun ist" suchen. Würde jemand Ant_222 Antwort empfehlen?
fantastische
3
Wenn Sie wirklich nicht weiterkommen, können Sie dennoch einen Typalias außerhalb Ihres Namespace erstellen. Externe Aliase werden nur benötigt, wenn Sie zwei vollständig identische vollständige Bezeichner haben (Namespace + Klassenname).
Geoffrey
3
Alles oben Genannte ist auf Wiedersehen und Meinung. Die Tatsache ist , dass man es nicht tun sollte , weil der C # -Compiler es falsch verstanden wird , trotz ganz klar gesagt, was los ist . ZB bezieht sich using Foo.Bar;später Bar bganz klar auf Bareine Klasse (oder Aufzählung) innerhalb des Namespace Foo.Bar. Der wahre Grund, dies nicht zu tun, ist lediglich, dass der C # -Compiler es nicht richtig versteht, was schrecklich überraschend und unglücklich ist. Alles andere ist ein Ratschlag im Wollstil.
TJ Crowder
2
Ich verstehe es nicht Warum ist Foo.Foo nicht eindeutig? Sie sagen dem Compiler direkt, dass Sie in diesem speziellen Fall die Klasse Foo aus dem Namespace Foo verwenden möchten. Nein?
GuardianX
14

Wenn Sie dem Namespace und der Klasse denselben Namen geben, kann dies den Compiler verwirren, wie andere gesagt haben.

Wie soll man es dann benennen?

Wenn der Namespace mehrere Klassen hat, suchen Sie einen Namen, der alle diese Klassen definiert.

Wenn der Namespace nur eine Klasse hat (und daher die Versuchung, ihm denselben Namen zu geben), benennen Sie den Namespace ClassName NS . So benennt Microsoft zumindest ihre Namespaces.

Gehe zu
quelle
4
Haben Sie ein Beispiel für einen solchen Namespace von Microsoft?
Sunefred
Ich muss es suchen und zu dir zurückkommen.
GoTo
@sunefred Ich habe es gesucht, aber ich konnte es nicht finden. Aber ich erinnere mich definitiv daran, es in der Dokumentation gesehen zu haben. Ich denke, es gibt nicht viele Fälle, in denen Sie eine einzelne Klasse in einem Namespace haben möchten.
GoTo
9

Ich würde vorschlagen, dass Sie den Rat befolgen, den ich verwendet habe microsoft.public.dotnet.languages.csharp, MyLib.ScenegraphUtil.Scenegraphund MyLib.ScenegraphUtil.*.

Ant_222
quelle
8

CA1724: Type Names Should Not Match Namespaces ...

Wenn Sie der Codeanalyse folgen, um eine ordnungsgemäße Codierung zu gewährleisten, lautet diese Regel grundsätzlich, nicht das zu tun, was Sie versuchen. Die Codeanalyse ist sehr nützlich , um potenzielle Probleme zu finden.

Myermian
quelle
4

Nur meine 2 Cent hinzufügen:

Ich hatte folgende Klasse:

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

Der Client wurde folgendermaßen geschrieben:

using Foo;

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

Da der Fehler GetFoo die Ausgabe nicht zurückgibt, anstatt den Parameter out zu verwenden, konnte der Compiler den Datentyp Foo.Bar [] nicht auflösen. Es wurde der Fehler zurückgegeben: Typ oder Namespace Foo.Bar konnte nicht gefunden werden.

Es scheint, dass beim Versuch, es zu kompilieren, Foo als Klasse aufgelöst wurde und keine eingebettete Klassenleiste in der Klasse Foo gefunden wurde. Es konnte auch kein Namespace namens Foo.Bar gefunden werden. Es konnte keine Klassenleiste im Namespace Foo gesucht werden. Die Punkte in einem Namensraum sind NICHT syntaktisch. Die gesamte Zeichenfolge ist ein Token, nicht die durch die Punkte begrenzten Wörter.

Dieses Verhalten wurde von VS 2015 mit .Net 4.6 gezeigt

Steve
quelle
3

Auch wenn ich anderen Antworten darin zustimme, dass Sie Ihre Klasse nicht wie Ihren Namespace benennen sollten, gibt es Zeiten, in denen Sie solche Anforderungen nicht erfüllen können.

In meinem Fall war ich zum Beispiel nicht die Person, die eine solche Entscheidung traf, deshalb musste ich einen Weg finden, damit es funktioniert.

Für diejenigen, die weder den Namespace-Namen noch den Klassennamen ändern können, ist dies eine Möglichkeit, Ihren Code zum Laufen zu bringen.

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

Grundsätzlich habe ich Namespace- "Aliase" erstellt, wodurch ich die Klasse vollständig qualifizieren konnte und die "Verwirrung" in Visual Studio verschwand.

HINWEIS: Sie sollten diesen Namenskonflikt vermeiden, wenn Sie dies in Ihrem Steuerelement tun. Sie sollten die erwähnte Technik nur verwenden, wenn Sie nicht die Kontrolle über die betreffenden Klassen und Namespaces haben.

Jonathan Alfaro
quelle
2
Ich habe dafür gestimmt, weil es eine interessante Lösung für eine unvollkommene Welt war.
user430788
2

Alter Beitrag, aber hier gehe ich mit einer anderen Idee, die jemandem helfen könnte:

"... aber es scheint die einzige Möglichkeit zu sein, alle anderen Klassen zu inneren Klassen von Scenegraph in der Datei Scenegraph.cs zu machen, und das ist einfach zu unhandlich."

Dies ist wirklich die bessere Implementierung für eine Reihe von Szenarien. Ich stimme jedoch zu, dass es ärgerlich ist, den gesamten Code in derselben CS-Datei zu haben (gelinde gesagt).

Sie können das Problem lösen, indem Sie die Basisklasse zu einer "Teilklasse" machen und dann die inneren Klassen in ihren eigenen Dateien erstellen (denken Sie daran, dass sie das Basisklassenkomplement deklarieren und dann mit der spezifischen inneren Klasse fortfahren müssen für diese Datei).

Etwas wie...

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

Ich denke, dass dies der nächste Schritt ist, um die saubere Implementierung innerer Klassen zu erreichen, ohne alles in einer riesigen und unordentlichen Datei überladen zu müssen.

Marcelo Myara
quelle
2

Wie andere bereits gesagt haben, empfiehlt es sich, eine Klasse nicht so zu benennen wie ihren Namespace.

Hier sind einige zusätzliche Namensvorschläge aus einer Antwort von svick auf eine verwandte Frage "Gleicher Klassen- und Namespace-Name" im Software Engineering Stack Exchange:

Sie haben Recht, dass Sie den Namespace nicht so benennen sollten wie einen darin enthaltenen Typ. Ich denke, es gibt verschiedene Ansätze, die Sie verwenden können:

  • Pluralisieren: Model.DataSources.DataSource

Dies funktioniert besonders gut, wenn der Hauptzweck des Namespace darin besteht, Typen zu enthalten, die vom gleichen Basistyp erben oder dieselbe Schnittstelle implementieren.

  • Verkürzen: Model.QueryStorage

Wenn ein Namespace nur eine kleine Anzahl von Typen enthält, benötigen Sie diesen Namespace möglicherweise überhaupt nicht.

  • Machen Sie Unternehmen: Model.ProjectSystem.Project

Dies kann insbesondere für Funktionen funktionieren, die ein wichtiger Bestandteil Ihres Produkts sind, sodass sie ihren eigenen Namen verdienen.

(Beachten Sie, dass die oben genannte Antwort Verwendungen Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.und Model.Project.Projectals Beispiele statt MyLib.Scenegraph.Scenegraph.)

(Ich fand auch die anderen Namensvorschläge in den anderen Antworten hier hilfreich.)

Sonny
quelle
1

Es passiert, wenn es die Hauptklasse des Namespace ist. Es ist also eine Motivation, den Namespace in eine Bibliothek zu stellen. Dann verschwindet das Problem, wenn Sie dem Namespace-Namen 'Lib' hinzufügen ...

namespace SocketLib
{
    class Socket
    {
Paul Sumpner
quelle