Dlaczego „używa Systemu”; nie uważane za złą praktykę?

47

Mam doświadczenie w języku C ++ i w pełni rozumiem i zgadzam się z odpowiedziami na to pytanie: Dlaczego „używanie przestrzeni nazw std;” uważane za złą praktykę?

Jestem więc zaskoczony, że mając trochę doświadczenia z C #, widzę tam dokładnie coś przeciwnego: using Some.Namespace;jest dosłownie wszędzie używany. Za każdym razem, gdy zaczynasz używać typu, najpierw dodajesz dyrektywę using dla jego przestrzeni nazw (jeśli jeszcze go nie ma). Nie pamiętam, że widziałem .csplik, od którego się nie zaczął using System; using System.Collections.Generic; using X.Y.Z; etc.... W rzeczywistości, jeśli dodasz nowy plik za pomocą kreatora Visual Studio, automatycznie doda tam niektóre dyrektywy, nawet jeśli w ogóle ich nie potrzebujesz. Tak więc, podczas gdy w społeczności C ++ jesteś zasadniczo zlinczowany, C # nawet zachęca do robienia tego. Przynajmniej tak mi się wydaje.

Teraz rozumiem, że używanie dyrektyw w C # i C ++ nie jest dokładnie tym samym. Rozumiem również, że jedna z najgorszych rzeczy, które możesz zrobić using namespacew C ++, mianowicie umieszczenie go w pliku nagłówkowym, nie ma równorzędnego odpowiednika w języku C # z powodu braku koncepcji plików nagłówkowych i #include.

Jednak pomimo różnic, korzystanie z dyrektyw w C # i C ++ służy temu samemu celowi, który trzeba pisać tylko SomeTypecały czas, a nie znacznie dłużej Some.Namespace.SomeType(w C ++ ::zamiast zamiast .). I w tym samym celu również niebezpieczeństwo wydaje mi się takie samo: nazewnictwo kolizji.

W najlepszym przypadku powoduje to błąd kompilacji, więc „tylko” trzeba go naprawić. W najgorszym przypadku nadal się kompiluje, a kod po cichu robi inne rzeczy, niż zamierzałeś. Więc moje pytanie brzmi: dlaczego (najwyraźniej) używają dyrektyw uważanych za tak nierównomiernie złe w C # i C ++?

Kilka pomysłów na odpowiedź, którą mam (ale żadna z nich tak naprawdę mnie nie satysfakcjonuje):

  • Przestrzenie nazw są zwykle znacznie dłuższe i znacznie bardziej zagnieżdżone w C # niż w C ++ ( stdvs. System.Collection.Generic). Tak więc istnieje większe pragnienie i większy zysk w odczekaniu kodu w ten sposób. Ale nawet jeśli jest to prawda, ten argument ma zastosowanie tylko wtedy, gdy spojrzymy na standardowe przestrzenie nazw. Niestandardowe mogą mieć dowolną krótką nazwę, zarówno w języku C #, jak i C ++.

  • Przestrzenie nazw wydają się być znacznie bardziej „drobnoziarniste” w C # niż w C ++. Jako przykład, w C ++ cała biblioteka standardowa jest zawarta w std(plus kilka drobnych zagnieżdżonych nazw podoba chrono), natomiast w C # trzeba System.IO, System.Threading, System.Textitd. Tak więc, ryzyko wystąpienia kolizji nazewnictwa jest mniejszy. Jest to jednak tylko przeczucie. Tak naprawdę nie policzyłem, ile nazw „importujesz” za pomocą using namespace stdi using System. I znowu, nawet jeśli jest to prawda, ten argument ma zastosowanie tylko w przypadku standardowych przestrzeni nazw. Własne mogą być zaprojektowane tak drobnoziarniste, jak chcesz, zarówno w języku C #, jak i C ++.

Czy jest więcej argumentów? Szczególnie interesują mnie faktyczne twarde fakty (jeśli takie istnieją), a nie opinie.

sebrockm
źródło
2
@ Timo OP wyraźnie nie pyta o zanieczyszczenie nagłówka.
Konrad Rudolph
1
Zakładałem, że było tak, ponieważ nie ma konkurencji dla globalnej przestrzeni nazw w takim samym stopniu, jak w C ++ (głównie ze względu na standardową bibliotekę C). Ale czekam na odpowiedzi tych, którzy wiedzą najlepiej.
Wyck
2
@ThomasWeller W C ++ to oczywiste. W języku C # rozważ metodę rozszerzeń, Ext(this T t, long l)która nazywa się via t.Ext(0). Jeśli następnie dodasz inną przestrzeń nazw zawierającą metodę rozszerzenia Ext(this T t, int i), zostanie ona wywołana zamiast tego. Ale nie jestem ekspertem w C # (jeszcze).
sebrockm
2
@Franck, nawet jeśli przyznam ci ten punkt, to ten sam argument dotyczy C ++, dodatkowo popychając moje pytanie, czy nie widzę różnicy między C ++ i C #
sebrockm
3
@Franck C ++ rzuci ci błąd kompilatora w przypadku niejasności. Jak również C #.
Timo

Odpowiedzi:

28

Dlaczego „używa Systemu”; nie uważane za złą praktykę?

„using System;” nie jest powszechnie uważany za złą praktykę. Zobacz na przykład: Dlaczego nie użyć dyrektywy „using” w języku C #?

Ale może być prawdą, że nie jest uważany za tak zły jak using namespace std. Prawdopodobnie ponieważ:

  1. C # nie ma plików nagłówkowych. Rzadko „dołącza się” jeden plik źródłowy w języku C # do drugiego za pomocą preprocesora.

  2. stdprzestrzeń nazw jest prawie płaska, tzn. są w niej prawie wszystkie standardowe funkcje biblioteczne, typy i zmienne (istnieje kilka wyjątków, takich jak podprzestrzeń nazw systemu plików). Zawiera bardzo, bardzo dużą liczbę identyfikatorów. O ile mi wiadomo, Systemzawiera znacznie mniej nazw, a zamiast tego ma więcej pod-nazw.

  3. W języku C # nie ma funkcji globalnych ani zmiennych. W związku z tym liczba globalnych identyfikatorów jest zazwyczaj dość mała w przeciwieństwie do C ++, który je ma: Ponadto typowe jest używanie bibliotek C (często pośrednio), które nie mają przestrzeni nazw, a zatem umieszczają wszystkie ich nazwy w globalnej przestrzeń nazw.

  4. O ile mi wiadomo, C # nie ma wyszukiwania zależnego od argumentów. ADL w połączeniu z ukrywaniem nazw, przeciążaniem itp. Może powodować przypadki, w których niektóre programy nie są dotknięte konfliktem nazw, podczas gdy inne są subtelnie dotknięte, a wyłapanie wszystkich przypadków narożnych nie jest możliwe przy testowaniu.

Z powodu tych różnic „używa Systemu”; ma niższą szansę na konflikt nazw niż using namespace std.


Ponadto „importowanie” przestrzeni nazw jest w pewnym sensie samonapędzającą się konwencją: jeśli konwencjonalne jest importowanie standardowej przestrzeni nazw, wówczas programiści będą tradycyjnie starali się unikać wybierania nazw z tej przestrzeni nazw dla własnych identyfikatorów, co pomaga zmniejszyć problemy z taka konwencja.

Jeśli taki import zostanie uznany za złą praktykę, programiści będą mniej skłonni nawet próbować uniknąć konfliktów z importowanymi przestrzeniami nazw. Jako takie, konwencje mają tendencję do spolaryzowania zarówno w stosunku do praktyki, jak i przeciw niej, nawet jeśli waga argumentów między wyborami była początkowo subtelna.

eerorika
źródło
3
Dotyczy to tylko potencjalnych wad otwierania przestrzeni nazw. To początek, ale myślę, że musimy również wziąć pod uwagę zalety: w przypadku C ++ w większości przypadków zapisuje pięć znaków ( std::). W języku C # jest znacznie więcej ( System.ma „tylko” 7 znaków, ale inne, zagnieżdżone przestrzenie nazw mają o wiele więcej znaków, a zapisanie ich wszędzie sprawiłoby, że kod byłby całkowicie nieczytelny).
Konrad Rudolph
Czy nie jest tak również, że rozdzielczość przeciążenia w C # jest milsza niż ta w C ++, a błędy kompilatora wynikają z dużej niejednoznaczności? (W żadnym wypadku nie krytykuje twojej odpowiedzi, która wydaje się wiarygodna.)
Batszeba
3
@KonradRudolph Gdyby wady zostały uznane za znaczące, a ilość pisania na równi (w porównaniu do ilości pisania std::), czy nie byłoby typowym stylem stosowanie using Sys = System;zamiast nie-aliasu przestrzeni nazw using?
eerorika
2
@Bathsheba odnośnie do „autorytatywnego”, chciałbym oświadczyć, że wiem bardzo mało o C #, a moja odpowiedź oparta jest na znajomości C ++ i kilku wyszukiwaniach Google o C #. Byłbym wdzięczny, gdyby ktoś faktycznie sprawdził części C # :)
eerorika
2
Jeśli chodzi o część ADL: C # ma metody rozszerzenia. Jest to inny projekt niż ADL, ale mają te same problemy dotyczące konfliktów nazw.
Timo
-2

Jednak pomimo różnic, korzystanie z dyrektyw w C # i C ++ służy temu samemu celowi, który wymaga ciągłego wpisywania SomeType przez cały czas, a nie znacznie dłuższego Some.Namespace.SomeType (w C ++ z :: zamiast.). I w tym samym celu wydaje mi się, że to także niebezpieczeństwo: nazewnictwo kolizji.

Tak, ale nie wyeksportowałeś tego niebezpieczeństwa (czytaj: zmuszanie innych do radzenia sobie z nim), z powodu:

Teraz rozumiem, że używanie dyrektyw w C # i C ++ nie jest dokładnie tym samym. Rozumiem również, że jedna z najbardziej nieprzyjemnych rzeczy, które można zrobić z użyciem przestrzeni nazw w C ++, mianowicie umieszczenie jej w pliku nagłówkowym, nie ma odpowiednika w języku C # z powodu braku koncepcji plików nagłówkowych i #include.

To raczej inna kategoria rzeczy.

Ponadto C ++ nie jest „zaprojektowany” do programowania w IDE w taki sam sposób jak C #. C # jest zasadniczo zawsze napisany w Visual Studio z Intellisense i tak dalej. Jest przeznaczony do użycia w ten sposób przez ludzi, którzy go stworzyli. Niezależnie od tego, ile osób używa IDE do programowania w C ++, nie jest on zaprojektowany z tym przypadkiem użycia jako przeważającej troski.

Przestrzenie nazw wydają się być znacznie bardziej „drobnoziarniste” w C # niż w C ++.

Tak też. using namespace stdi using System.Collection.Genericsą nieporównywalne.

Więc nie porównuj ich!

Asteroidy Ze Skrzydłami
źródło
2
To nie odpowiada na obawy OP, które wyraźnie nie dotyczą otwierania przestrzeni nazw w nagłówkach, ale w plikach implementacyjnych .
Konrad Rudolph
2
@KonradRudolph Porada, której należy unikać using namespace stdw C ++ dotyczy głównie plików nagłówkowych. Odpowiedź jest taka, że ​​nie dotyczy to języka C #.
Asteroidy ze skrzydłami
8
@AsteroidsWithWings rada, której należy unikać, z using namespace stdpewnością nie dotyczy głównie nagłówków. Używanie go w nagłówkach jest niebezpieczne. Używanie go w swoich implementacjach jest odradzane.
Tommy Andersen
1
Porada, której należy unikać using namespace ...w c ++, dotyczy unikania kolizji nazewnictwa, usingdyrektywa w C # wprowadza również możliwość nazewnictwa kolizji, więc dlaczego by tego nie uniknąć? Mimo, że są różne wdrożenia.
Tommy Andersen
@TommyAndersen, jak trudno jest rozwiązać taki konflikt, jeśli tak się stanie? To zajmuje sekundę. Ponieważ usingdeklaracje w języku C # są na plik, który definiuje pojedynczy typ / klasę, a typ ten ma zwykle związek ze stosunkowo wąskim zestawem koncepcji domeny aplikacji (najlepiej zasada pojedynczej odpowiedzialności), prawdopodobieństwo takich kolizji przestrzeni nazw jest bardzo niskie. Ale kiedy to się stanie, można je łatwo naprawić. Typowe narzędzia programistyczne .NET / IDE bardzo w tym pomogą. Zastanów się nad całym ekosystemem programistycznym, który ma na celu zwiększenie produktywności, łącząc najlepsze z wielu działań programistycznych
AKornich,