Warum wird "System verwendet"? nicht als schlechte Praxis angesehen?

47

Ich habe einen C ++ - Hintergrund und verstehe die Antworten auf diese Frage voll und ganz und stimme ihnen zu: Warum wird der Namespace std verwendet? als schlechte Praxis angesehen?

Ich bin erstaunt, dass ich nach einigen Erfahrungen mit C # genau das Gegenteil sehe: using Some.Namespace;Wird buchstäblich überall verwendet. Wenn Sie einen Typ verwenden, fügen Sie zuerst eine using-Direktive für seinen Namespace hinzu (falls diese noch nicht vorhanden ist). Ich kann mich nicht erinnern, eine .csDatei gesehen zu haben, die nicht damit begonnen hat using System; using System.Collections.Generic; using X.Y.Z; etc.... Wenn Sie eine neue Datei über den Visual Studio-Assistenten hinzufügen, werden dort automatisch einige mithilfe von Anweisungen hinzugefügt, auch wenn Sie diese möglicherweise überhaupt nicht benötigen. Während Sie in der C ++ - Community im Grunde genommen gelyncht werden, empfiehlt C # dies sogar. Zumindest erscheint es mir so.

Jetzt verstehe ich, dass die Verwendung von Direktiven in C # und C ++ nicht genau dasselbe ist. Ich verstehe auch, dass eines der schlimmsten Dinge, mit denen Sie using namespacein C ++ arbeiten können, nämlich das Einfügen in eine Header-Datei, aufgrund des Fehlens eines Konzepts für Header-Dateien und in C # kein gleichwertiges Gegenstück hat #include.

Trotz ihrer Unterschiede dient die Verwendung von Direktiven in C # und C ++ demselben Zweck, der nur die SomeTypeganze Zeit eingegeben werden muss und nicht der viel längere Some.Namespace.SomeType(in C ++ mit ::statt .). Und mit dem gleichen Zweck scheint mir auch die Gefahr dieselbe zu sein: Kollisionen zu benennen.

Im besten Fall führt dies zu einem Kompilierungsfehler, sodass Sie ihn "nur" beheben müssen. Im schlimmsten Fall wird es immer noch kompiliert und der Code macht stillschweigend andere Dinge, als Sie beabsichtigt hatten. Meine Frage lautet also: Warum werden (anscheinend) Direktiven verwendet, die in C # und C ++ als so ungleich schlecht angesehen werden?

Einige Ideen für eine Antwort, die ich habe (keine davon befriedigt mich jedoch wirklich):

  • Namespaces sind in C # in der Regel viel länger und viel stärker verschachtelt als in C ++ ( stdvs. System.Collection.Generic). Es gibt also mehr Lust und mehr Gewinn, den Code auf diese Weise zu entrauschen. Aber selbst wenn dies zutrifft, gilt dieses Argument nur, wenn wir uns die Standard-Namespaces ansehen. Benutzerdefinierte können in C # und C ++ einen beliebigen Kurznamen haben.

  • Namespaces scheinen in C # viel "feinkörniger" zu sein als in C ++. Als Beispiel ist in C ++ die gesamte Standardbibliothek enthalten in std(plus einige kleine verschachtelte Namensräume wie chrono) , während in C # Sie haben System.IO, System.Threading, System.Textetc. So wird das Risiko von Namenskollisionen mit kleiner. Dies ist jedoch nur ein Bauchgefühl. Ich habe nicht gezählt, wie viele Namen Sie mit using namespace stdund "importieren" using System. Auch wenn dies zutrifft, gilt dieses Argument nur für die Standard-Namespaces. Ihre eigenen können sowohl in C # als auch in C ++ so feinkörnig gestaltet werden, wie Sie möchten.

Gibt es mehr Argumente? Ich interessiere mich besonders für aktuelle harte Fakten (falls vorhanden) und nicht so sehr für Meinungen.

sebrockm
quelle
2
@ Timo Das OP fragt ausdrücklich nicht nach der Verschmutzung der Header.
Konrad Rudolph
1
Ich nahm an, dass dies daran liegt, dass es keine Konkurrenz für den globalen Namespace in dem Maße gibt, wie es ihn in C ++ gibt (hauptsächlich aufgrund der C-Standardbibliothek). Aber ich erwarte die Antworten derer, die es am besten wissen.
Wyck
2
@ ThomasWeller In C ++ ist es offensichtlich. Betrachten Sie in C # eine Erweiterungsmethode Ext(this T t, long l), die via aufgerufen wird t.Ext(0). Wenn Sie dann einen anderen Namespace hinzufügen, der eine Erweiterungsmethode enthält Ext(this T t, int i), wird dieser stattdessen aufgerufen. Aber ich bin (noch) kein Experte für C #.
sebrockm
2
@Franck Selbst wenn ich Ihnen diesen Punkt gewährt habe, gilt das gleiche Argument für C ++, was meine Frage weiter
aufwirft
3
@Franck C ++ wirft bei Mehrdeutigkeit einen Compilerfehler auf Sie. Sowie C #.
Timo

Antworten:

28

Warum wird "System verwendet"? nicht als schlechte Praxis angesehen?

"using System;" wird nicht allgemein als schlechte Praxis angesehen. Siehe zum Beispiel: Warum würden Sie die 'using'-Direktive nicht in C # verwenden?

Aber es kann wahr sein, dass es nicht ganz so schlimm ist wie using namespace std. Vielleicht weil:

  1. C # hat keine Header-Dateien. Es ist ungewöhnlich, eine C # -Quelldatei mit einem Vorprozessor in eine andere "einzuschließen".

  2. stdDer Namespace ist nahezu flach, dh fast alle Standardbibliotheksfunktionen, -typen und -variablen sind darin enthalten (es gibt nur wenige Ausnahmen wie den Subsystem-Namespace des Dateisystems). Es enthält sehr, sehr viele Bezeichner. SystemEnthält nach meinem Verständnis viel weniger Namen und stattdessen mehr Sub-Namespaces.

  3. In C # gibt es keine globalen Funktionen oder Variablen. Daher ist die Anzahl der globalen Bezeichner im Gegensatz zu C ++, das diese hat, normalerweise recht gering: Darüber hinaus ist es typisch, C-Bibliotheken (häufig indirekt) zu verwenden, die keine Namespaces haben, und daher alle ihre Namen in die globalen zu setzen Namespace.

  4. Soweit ich weiß, hat C # keine argumentabhängige Suche. ADL in Verbindung mit dem Ausblenden, Überladen usw. von Namen kann zu Fällen führen, in denen einige Programme nicht von einem Namenskonflikt betroffen sind, während andere subtil betroffen sind und das Abfangen aller Eckfälle beim Testen nicht möglich ist.

Aufgrund dieser Unterschiede wird "using System" verwendet. hat eine geringere Wahrscheinlichkeit für Namenskonflikte als using namespace std.


Das "Importieren" von Namespaces ist in gewisser Weise eine sich selbst aufrechterhaltende Konvention: Wenn es üblich ist, einen Standard-Namespace zu importieren, versuchen Programmierer herkömmlicherweise , die Auswahl von Namen aus diesem Namespace für ihre eigenen Bezeichner zu vermeiden, um Probleme mit zu reduzieren solche Konvention.

Wenn ein solcher Import als schlechte Praxis angesehen wird, ist es weniger wahrscheinlich, dass Programmierer versuchen, Konflikte mit importierten Namespaces zu vermeiden. Konventionen tendieren daher dazu, entweder für oder gegen die Praxis zu polarisieren, selbst wenn die Gewichtung der Argumente zwischen den Entscheidungen ursprünglich subtil war.

Eerorika
quelle
3
Dies berücksichtigt nur mögliche Nachteile beim Öffnen von Namespaces. Das ist ein Anfang, aber ich denke, wir müssen auch die Vorteile berücksichtigen: Im Fall von C ++ werden in den meisten Fällen fünf Zeichen gespeichert ( std::). In C # ist es wesentlich mehr ( System.hat "nur" 7 Zeichen, aber andere verschachtelte Namespaces haben viel mehr Zeichen, und wenn Sie sie überall ausschreiben, wird der Code vollständig unlesbar).
Konrad Rudolph
Ist es nicht auch so, dass die C # -Überlastungsauflösung freundlicher ist als die in C ++ und durch Compilerfehler viel Unklarheit entsteht? (Auf keinen Fall eine Kritik an Ihrer Antwort, die maßgeblich erscheint.)
Bathseba
3
@KonradRudolph Wenn die Nachteile als signifikant angesehen würden und die Anzahl der Eingaben gleichermaßen (im Vergleich zur Anzahl der Eingaben std::), wäre es nicht ein typischer Stil, using Sys = System;stattdessen den Namespace zu verwenden, der Nicht-Alias ​​verschmutzt using?
Eerorika
2
@Bathsheba in Bezug auf "maßgeblich" möchte ich ablehnen, dass ich sehr wenig über C # weiß, und meine Antwort basiert auf Kenntnissen in C ++ und einigen Google-Suchanfragen über C #. Ich würde mich
freuen,
2
In Bezug auf den ADL-Teil: C # verfügt über Erweiterungsmethoden. Es ist ein anderes Design als ADL, aber sie haben dieselben Probleme in Bezug auf Namenskonflikte.
Timo
-2

Trotz ihrer Unterschiede dient die Verwendung von Direktiven in C # und C ++ demselben Zweck, da nur SomeType ständig eingegeben werden muss und nicht der viel längere Some.Namespace.SomeType (in C ++ mit :: anstelle von.). Und mit dem gleichen Ziel scheint mir auch die Gefahr zu bestehen: Kollisionen zu benennen.

Ja, aber Sie haben diese Gefahr nicht exportiert (lesen Sie: andere dazu zwingen, damit umzugehen), weil:

Jetzt verstehe ich, dass die Verwendung von Anweisungen in C # und C ++ nicht genau dasselbe ist. Ich verstehe auch, dass eines der schlimmsten Dinge, die Sie mit der Verwendung von Namespace in C ++ tun können, nämlich das Einfügen in eine Header-Datei, in C # keine Entsprechung hat, da es kein Konzept für Header-Dateien und #include gibt.

Es ist also eher eine andere Kategorie von Dingen.

Außerdem ist C ++ nicht so konzipiert, dass es in einer IDE wie C # entwickelt wird. C # wird grundsätzlich immer in Visual Studio mit Intellisense und so weiter geschrieben. Es wurde entwickelt, um von den Menschen, die es erstellt haben, auf diese Weise verwendet zu werden. Unabhängig davon, wie viele Benutzer eine IDE für die Entwicklung in C ++ verwenden, ist sie nicht mit diesem Anwendungsfall als überwältigendes Problem konzipiert.

Namespaces scheinen in C # viel "feinkörniger" zu sein als in C ++.

Ja das auch. using namespace stdund using System.Collection.Genericsind unvergleichlich.

Also vergleiche sie nicht!

Asteroiden mit Flügeln
quelle
2
Dies beantwortet nicht die Bedenken von OP, bei denen es ausdrücklich nicht darum geht, Namespaces in Headern, sondern in Implementierungsdateien zu öffnen .
Konrad Rudolph
2
@KonradRudolph Der using namespace stdin C ++ zu vermeidende Rat bezieht sich hauptsächlich auf Header-Dateien. Die Antwort ist, dass dies in C # nicht gilt.
Asteroiden mit Flügeln
8
@AsteroidsWithWings Bei den zu vermeidenden Ratschlägen using namespace stdgeht es sicherlich nicht hauptsächlich um Header. Die Verwendung in Headern ist gefährlich. Von der Verwendung in Ihren Implementierungen wird abgeraten.
Tommy Andersen
1
Der Ratschlag, den Sie using namespace ...in c ++ vermeiden sollten, besteht darin, Namenskollisionen zu vermeiden. Die usingAnweisung in C # führt auch die Möglichkeit ein, Kollisionen zu benennen. Warum sollten Sie sie dann nicht vermeiden? Auch wenn dort die Umsetzung unterschiedlich ist.
Tommy Andersen
@ TommyAndersen, wie schwierig ist es, einen solchen Konflikt zu lösen, wenn er auftritt? Es dauert eine Sekunde. Da C # using-Deklarationen pro Datei vorliegen, die einen einzelnen Typ / eine einzelne Klasse definiert, und der Typ normalerweise mit einem relativ engen Satz von Anwendungsdomänenkonzepten (im Idealfall dem Prinzip der einzelnen Verantwortung) zu tun hat, ist die Wahrscheinlichkeit solcher Namespace-Konflikte äußerst gering. Aber wenn passieren, sind leicht zu beheben. Gängige .NET-Entwicklungstools / IDE helfen Ihnen dabei sehr. Betrachten Sie das gesamte Entwicklungsökosystem, das Sie produktiver machen soll, indem Sie das Beste aus mehreren Entwicklungsaktivitäten kombinieren
AKornich,