Ich habe StyleCop über einen C # -Code ausgeführt und es wird immer wieder gemeldet, dass sich meine using
Anweisungen im Namespace befinden sollten.
Gibt es einen technischen Grund, die using
Direktiven innerhalb und nicht außerhalb des Namespace zu platzieren?
c#
.net
namespaces
stylecop
code-organization
benPearce
quelle
quelle
using
Aussagen ; Sie sindusing
Richtlinien . Eineusing
Anweisung ist andererseits eine Sprachstruktur, die zusammen mit anderen Anweisungen innerhalb eines Methodenkörpers usw. auftritt. Als Beispielusing (var e = s.GetEnumerator()) { /* ... */ }
gilt eine Anweisung, die lose mit der identisch istvar e = s.GetEnumerator(); try { /* ... */ } finally { if (e != null) { e.Dispose(); } }
.using
Anweisungen in dienamespace
Deklarationen in ihren internen Codierungsrichtlinien aufzunehmenAntworten:
Es gibt tatsächlich einen (subtilen) Unterschied zwischen den beiden. Stellen Sie sich vor, Sie haben den folgenden Code in File1.cs:
Stellen Sie sich nun vor, jemand fügt dem Projekt eine weitere Datei (File2.cs) hinzu, die folgendermaßen aussieht:
Der Compiler sucht,
Outer
bevor er dieseusing
Anweisungen außerhalb des Namespace betrachtet, und findetOuter.Math
stattdessen stattSystem.Math
. Leider (oder vielleicht zum Glück?) HatOuter.Math
keinPI
Mitglied, so dass File1 jetzt kaputt ist.Dies ändert sich, wenn Sie die
using
Namespace-Deklaration wie folgt einfügen:Jetzt sucht der Compiler
System
vor dem SuchenOuter
, findetSystem.Math
und alles ist gut.Einige würden argumentieren, dass
Math
dies ein schlechter Name für eine benutzerdefinierte Klasse sein könnte, da bereits eine vorhanden istSystem
. Der Punkt hier ist nur , dass es ist ein Unterschied, und es wirkt sich auf die Wartbarkeit des Codes.Es ist auch interessant festzustellen, was passiert, wenn
Foo
es sich im NamespaceOuter
befindet und nichtOuter.Inner
. In diesem Fall wird durch HinzufügenOuter.Math
von Datei2 Datei1 unterbrochen, unabhängig davon, wohin dasusing
geht. Dies bedeutet, dass der Compiler den innersten umschließenden Namespace durchsucht, bevor er eineusing
Direktive betrachtet.quelle
Dieser Thread hat bereits einige großartige Antworten, aber ich denke, ich kann mit dieser zusätzlichen Antwort ein wenig mehr Details bringen.
Denken Sie zunächst daran, dass eine Namespace-Deklaration mit Punkten wie:
ist völlig gleichbedeutend mit:
Wenn Sie möchten, können Sie
using
auf all diesen Ebenen Richtlinien festlegen. (Natürlich möchten wirusing
s nur an einem Ort haben, aber es wäre je nach Sprache legal.)Die Regel zum Auflösen des implizierten Typs kann lose wie folgt angegeben werden: Durchsuchen Sie zuerst den innersten "Bereich" nach einer Übereinstimmung. Wenn dort nichts gefunden wird, gehen Sie eine Ebene zum nächsten Bereich und suchen Sie dort und so weiter . bis eine Übereinstimmung gefunden wird. Wenn auf einer bestimmten Ebene mehr als eine Übereinstimmung gefunden wird und einer der Typen aus der aktuellen Assembly stammt, wählen Sie diesen aus und geben Sie eine Compiler-Warnung aus. Andernfalls geben Sie auf (Fehler beim Kompilieren).
Lassen Sie uns nun in einem konkreten Beispiel mit den beiden Hauptkonventionen explizit erläutern, was dies bedeutet.
(1) Bei Verwendung außerhalb:
Im obigen Fall
Ambiguous
erfolgt die Suche in der folgenden Reihenfolge , um herauszufinden, um welchen Typ es sich handelt:C
(einschließlich geerbter verschachtelter Typen)MyCorp.TheProduct.SomeModule.Utilities
MyCorp.TheProduct.SomeModule
MyCorp.TheProduct
MyCorp
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, undThirdParty
Die andere Konvention:
(2) Mit Verwendungen im Inneren:
Die Suche nach dem Typ erfolgt nun
Ambiguous
in dieser Reihenfolge:C
(einschließlich geerbter verschachtelter Typen)MyCorp.TheProduct.SomeModule.Utilities
System
,System.Collections.Generic
,System.Linq
,MyCorp.TheProduct
,MyCorp.TheProduct.OtherModule
,MyCorp.TheProduct.OtherModule.Integration
, undThirdParty
MyCorp.TheProduct.SomeModule
MyCorp
(Beachten Sie, dass dies
MyCorp.TheProduct
Teil von "3." war und daher zwischen "4." und "5." nicht benötigt wurde.)Abschließende Bemerkungen
Unabhängig davon, ob Sie die Verwendungen innerhalb oder außerhalb der Namespace-Deklaration platzieren, besteht immer die Möglichkeit, dass jemand später einem der Namespaces mit höherer Priorität einen neuen Typ mit identischem Namen hinzufügt.
Wenn ein verschachtelter Namespace denselben Namen wie ein Typ hat, kann dies zu Problemen führen.
Es ist immer gefährlich, die Verwendungen von einem Ort an einen anderen zu verschieben, da sich die Suchhierarchie ändert und möglicherweise ein anderer Typ gefunden wird. Wählen Sie daher eine Konvention und halten Sie sich daran, damit Sie die Verwendung nie verschieben müssen.
In den Vorlagen von Visual Studio werden die Verwendungen standardmäßig außerhalb des Namespace platziert (z. B. wenn VS eine neue Klasse in einer neuen Datei generiert).
Ein (kleiner) Vorteil von usings mit außen ist , dass Sie können dann die Verwendung von Richtlinien für ein globales Attribut nutzen, zum Beispiel
[assembly: ComVisible(false)]
statt[assembly: System.Runtime.InteropServices.ComVisible(false)]
.quelle
Wenn Sie es in die Namespaces einfügen, werden die Deklarationen lokal für diesen Namespace für die Datei (falls Sie mehrere Namespaces in der Datei haben). Wenn Sie jedoch nur einen Namespace pro Datei haben, spielt es keine große Rolle, ob sie nach draußen oder nach außen gehen innerhalb des Namespace.
quelle
using
Direktiven innerhalb vonnamespace
Blöcken können sich auf relative Namespaces beziehen, die auf dem umschließendennamespace
Block basieren .Laut Hanselman - Verwenden von Richtlinie und Laden von Baugruppen ... und anderen derartigen Artikeln gibt es technisch keinen Unterschied.
Ich bevorzuge es, sie außerhalb von Namespaces zu platzieren.
quelle
My style is to put them outside the namespaces.
- kaum eine Antwort überhaupt.Laut StyleCop-Dokumentation:
SA1200: UsingDirectivesMustBePlacedWithinNamespace
Ursache AC # mit der Direktive wird außerhalb eines Namespace-Elements platziert.
Regelbeschreibung Ein Verstoß gegen diese Regel tritt auf, wenn eine using-Direktive oder eine using-Alias-Direktive außerhalb eines Namespace-Elements platziert wird, es sei denn, die Datei enthält keine Namespace-Elemente.
Der folgende Code würde beispielsweise zu zwei Verstößen gegen diese Regel führen.
Der folgende Code würde jedoch nicht zu Verstößen gegen diese Regel führen:
Dieser Code wird ohne Compilerfehler sauber kompiliert. Es ist jedoch unklar, welche Version des Guid-Typs zugewiesen wird. Wenn die using-Direktive wie unten gezeigt in den Namespace verschoben wird, tritt ein Compilerfehler auf:
Der Code schlägt bei dem folgenden Compilerfehler fehl, der in der Zeile mit gefunden wird
Guid g = new Guid("hello");
CS0576: Der Namespace 'Microsoft.Sample' enthält eine Definition, die mit dem Alias 'Guid' in Konflikt steht.
Der Code erstellt einen Alias für den System.Guid-Typ namens Guid und einen eigenen Typ namens Guid mit einer passenden Konstruktorschnittstelle. Später erstellt der Code eine Instanz vom Typ Guid. Um diese Instanz zu erstellen, muss der Compiler zwischen den beiden unterschiedlichen Definitionen von Guid wählen. Wenn die using-Alias-Direktive außerhalb des Namespace-Elements platziert wird, wählt der Compiler die lokale Definition von Guid aus, die im lokalen Namespace definiert ist, und ignoriert die using-Alias-Direktive, die außerhalb des Namespace definiert ist, vollständig. Dies ist beim Lesen des Codes leider nicht ersichtlich.
Wenn die using-Alias-Direktive jedoch im Namespace positioniert ist, muss der Compiler zwischen zwei verschiedenen, widersprüchlichen Guid-Typen wählen, die beide im selben Namespace definiert sind. Beide Typen bieten einen passenden Konstruktor. Der Compiler kann keine Entscheidung treffen und kennzeichnet daher den Compilerfehler.
Das Platzieren der using-alias-Direktive außerhalb des Namespace ist eine schlechte Praxis, da dies in Situationen wie dieser zu Verwirrung führen kann, in denen nicht klar ist, welche Version des Typs tatsächlich verwendet wird. Dies kann möglicherweise zu einem Fehler führen, der möglicherweise schwer zu diagnostizieren ist.
Durch das Platzieren von using-alias-Direktiven im Namespace-Element wird dies als Fehlerquelle beseitigt.
Das Platzieren mehrerer Namespace-Elemente in einer einzelnen Datei ist im Allgemeinen eine schlechte Idee. In diesem Fall empfiehlt es sich jedoch, alle verwendeten Direktiven in jedem der Namespace-Elemente zu platzieren und nicht global am Anfang der Datei. Dies wird die Namespaces eng umrahmen und auch dazu beitragen, das oben beschriebene Verhalten zu vermeiden.
Es ist wichtig zu beachten, dass beim Schreiben von Code unter Verwendung von Anweisungen außerhalb des Namespace beim Verschieben dieser Anweisungen innerhalb des Namespace darauf geachtet werden sollte, dass dadurch die Semantik des Codes nicht geändert wird. Wie oben erläutert, kann der Compiler beim Platzieren von Direktiven mit Alias innerhalb des Namespace-Elements zwischen widersprüchlichen Typen auf eine Weise wählen, die nicht auftritt, wenn die Direktiven außerhalb des Namespace platziert werden.
So beheben Sie Verstöße Um einen Verstoß gegen diese Regel zu beheben, verschieben Sie alle Direktiven und Alias-Direktiven innerhalb des Namespace-Elements.
quelle
using
s außerhalb des Namespace. Inneresusing
sieht für mich so hässlich aus. :)Es gibt ein Problem beim Platzieren von using-Anweisungen im Namespace, wenn Sie Aliase verwenden möchten. Der Alias profitiert nicht von den früheren
using
Anweisungen und muss vollständig qualifiziert sein.Erwägen:
gegen:
Dies kann besonders ausgeprägt sein, wenn Sie einen langwierigen Alias wie den folgenden haben (so habe ich das Problem gefunden):
Mit
using
Anweisungen im Namespace wird es plötzlich:Nicht hübsch.
quelle
class
benötigen einen Namen (Kennung). Sie können keineusing
Direktive innerhalb einer Klasse haben, wie Sie angeben. Es muss sich auf einer Namespace-Ebene befinden, z. B. außerhalb der äußerstennamespace
oder nur innerhalb der innersten Ebenenamespace
(jedoch nicht innerhalb einer Klasse / Schnittstelle / etc.)using
Anweisungen fälschlicherweise falsch platziert. Ich habe es so bearbeitet, wie ich es beabsichtigt hatte. Vielen Dank für den Hinweis. Die Argumentation ist jedoch immer noch dieselbe.Wie Jeppe Stig Nielsen sagte , hat dieser Thread bereits großartige Antworten, aber ich dachte, dass diese ziemlich offensichtliche Subtilität auch erwähnenswert ist.
using
Anweisungen, die in Namespaces angegeben werden, können zu kürzerem Code führen, da sie nicht vollständig qualifiziert sein müssen, wie wenn sie außen angegeben werden.Das folgende Beispiel funktioniert, da sich die Typen
Foo
undBar
beide im selben globalen Namespace befindenOuter
.Angenommen, die Codedatei Foo.cs :
Und Bar.cs :
Das kann den äußeren Namespace in der
using
Direktive weglassen , kurz:quelle
Eine Falte, auf die ich gestoßen bin (die in anderen Antworten nicht behandelt wird):
Angenommen, Sie haben folgende Namespaces:
Wenn Sie
using Something.Other
außerhalb von a verwendennamespace Parent
, bezieht es sich auf das erste (Something.Other).Wenn Sie es jedoch innerhalb dieser Namespace-Deklaration verwenden, bezieht es sich auf die zweite (Parent.Something.Other)!
Es gibt eine einfache Lösung: Fügen Sie das
global::
Präfix " " hinzu: docsquelle
Die technischen Gründe werden in den Antworten diskutiert und ich denke, dass es am Ende um die persönlichen Vorlieben geht, da der Unterschied nicht so groß ist und es für beide Kompromisse gibt. Die Standardvorlage von Visual Studio zum Erstellen von
.cs
Dateien verwendetusing
Anweisungen außerhalb von Namespaces, zSie können stylecop anpassen, um
using
Anweisungen außerhalb von Namespaces zu überprüfen, indem Sie einestylecop.json
Datei im Stammverzeichnis der Projektdatei wie folgt hinzufügen :Sie können diese Konfigurationsdatei auf Lösungsebene erstellen und als "Vorhandene Linkdatei" zu Ihren Projekten hinzufügen, um die Konfiguration auch für alle Ihre Projekte freizugeben.
quelle
Eine andere Subtilität, von der ich nicht glaube, dass sie von den anderen Antworten abgedeckt wurde, ist, wenn Sie eine Klasse und einen Namespace mit demselben Namen haben.
Wenn Sie den Import im Namespace haben, wird die Klasse gefunden. Wenn sich der Import außerhalb des Namespace befindet, wird der Import ignoriert und die Klasse und der Namespace müssen vollständig qualifiziert sein.
quelle
Es ist eine bessere Vorgehensweise, wenn diejenigen, die standardmäßig " Referenzen " verwenden, die in Ihrer Quelllösung verwendet werden, außerhalb der Namespaces liegen sollten und diejenigen, die "neu hinzugefügte Referenzen" sind, eine gute Vorgehensweise sind, wenn Sie sie in den Namespace einfügen. Hiermit wird unterschieden, welche Referenzen hinzugefügt werden.
quelle