Istniejące standardy kodowania w dużym projekcie C # zawierają zasadę, że wszystkie nazwy typów są w pełni kwalifikowane, co zabrania stosowania dyrektywy „używającej”. Więc zamiast tego, co znajome:
using System.Collections.Generic;
.... other stuff ....
List<string> myList = new List<string>();
(Prawdopodobnie nie jest to zaskoczeniem, że var
jest również zabronione).
Kończę z:
System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string>();
To 134% wzrost pisania, przy czym żaden z tych wzrostów nie dostarcza użytecznych informacji. Moim zdaniem 100% wzrostu to hałas (bałagan), który faktycznie utrudnia zrozumienie.
Przez ponad 30 lat programowania widziałem taki standard zaproponowany raz lub dwa, ale nigdy nie został wdrożony. Uzasadnia to uzasadnienie. Osoba narzucająca standard nie jest głupia i nie sądzę, żeby był złośliwy. Które pozostawiają mylne informacje jako jedyna alternatywa, chyba że coś mi umknie.
Czy słyszałeś kiedyś o narzuceniu takiego standardu? Jeśli tak, jaki był tego powód? Czy możesz pomyśleć o argumentach innych niż „to głupie” lub „wszyscy inni zatrudniają using
”, które mogą przekonać tę osobę do usunięcia tego zakazu?
Rozumowanie
Przyczyny tego zakazu były:
- Najechanie kursorem myszy nad nazwę jest kłopotliwe, aby uzyskać w pełni kwalifikowany typ. Lepiej zawsze mieć zawsze w pełni kwalifikowany typ.
- Fragmenty kodu wysyłane pocztą e-mail nie mają w pełni kwalifikowanej nazwy, dlatego mogą być trudne do zrozumienia.
- Podczas przeglądania lub edycji kodu poza Visual Studio (na przykład Notepad ++) niemożliwe jest uzyskanie w pełni kwalifikowanej nazwy typu.
Twierdzę, że wszystkie trzy przypadki są rzadkie, a zmuszanie wszystkich do płacenia zaśmieconego i mniej zrozumiałego kodu tylko po to, aby uwzględnić kilka rzadkich przypadków, jest błędne.
Potencjalne problemy konfliktu przestrzeni nazw, które, jak się spodziewałem, były głównym problemem, nie zostały nawet wspomniane. Jest to szczególnie zaskakujące, ponieważ mamy przestrzeń nazw MyCompany.MyProject.Core
, co jest szczególnie złym pomysłem. Dawno temu nauczyłem się, że nazywanie czegokolwiek System
lub Core
w języku C # to szybka ścieżka do szaleństwa.
Jak zauważyli inni, konflikty przestrzeni nazw można łatwo rozwiązać przez refaktoryzację, aliasy przestrzeni nazw lub częściową kwalifikację.
źródło
Odpowiedzi:
Szersze pytanie:
Tak, słyszałem o tym, a używanie w pełni kwalifikowanych nazw obiektów zapobiega kolizjom nazw. Choć rzadko, kiedy się zdarzają, mogą być wyjątkowo trudni do rozgryzienia.
Przykład: Tego rodzaju scenariusz jest prawdopodobnie lepiej wyjaśniony na przykładzie.
Powiedzmy, że mamy dwa
Lists<T>
należące do dwóch oddzielnych projektów.Kiedy używamy w pełni kwalifikowanej nazwy obiektu, jasne jest, który z nich
List<T>
jest używany. Ta jasność oczywiście odbywa się kosztem gadatliwości.I możesz się kłócić: „Zaczekaj! Nikt nigdy nie użyłby dwóch takich list!” W tym miejscu przedstawię scenariusz konserwacji.
Masz napisany moduł
Foo
dla swojej korporacji, który korzysta z zatwierdzonej, zoptymalizowanej korporacjiList<T>
.Później nowy programista postanawia przedłużyć pracę, którą wykonałeś. Nie znając standardów firmy, aktualizują
using
blok:I możesz szybko zobaczyć, jak sprawy się psują.
Trywialne powinno być stwierdzenie, że możesz mieć dwie własnościowe klasy o tej samej nazwie, ale w różnych przestrzeniach nazw w ramach tego samego projektu. Więc nie chodzi tylko o kolizję z klasami dostarczonymi w ramach .NET Framework.
Rzeczywistość:
czy jest to prawdopodobne w większości projektów? Nie, nie bardzo. Ale gdy pracujesz nad dużym projektem z dużą ilością danych wejściowych, starasz się zminimalizować ryzyko wybuchu rzeczy.
Duże projekty z wieloma składającymi się zespołami to szczególny rodzaj bestii w świecie aplikacji. Reguły, które wydają się nieuzasadnione w przypadku innych projektów, stają się bardziej odpowiednie ze względu na strumienie danych wejściowych do projektu i prawdopodobieństwo, że osoby wnoszące wkład nie przeczytały wytycznych projektu.
Może się to również zdarzyć, gdy dwa duże projekty zostaną połączone. Jeśli oba projekty miały podobnie nazwane klasy, zobaczysz kolizje, gdy zaczniesz odwoływać się z jednego projektu do drugiego. Projekty mogą być zbyt duże, aby można je było refaktoryzować, lub zarząd nie zatwierdzi wydatków na sfinansowanie czasu poświęconego na refaktoryzację.
Alternatywy:
Chociaż nie pytałeś, warto zauważyć, że nie jest to świetne rozwiązanie problemu. Nie jest dobrym pomysłem tworzenie klas, które zderzą się bez deklaracji przestrzeni nazw.
List<T>
, w szczególności należy je traktować jako słowo zastrzeżone i nie należy używać ich jako nazw klas.Podobnie poszczególne przestrzenie nazw w projekcie powinny dążyć do uzyskania unikalnych nazw klas. Konieczność przypomnienia sobie, z jaką przestrzenią nazw
Foo()
pracujesz, to narzut umysłowy, którego najlepiej unikać. Powiedział inny sposób: posiadanieMyCorp.Bar.Foo()
iMyCorp.Baz.Foo()
zamiar potknąć programistów i najlepiej ich unikać.Jeśli nic więcej, możesz użyć częściowych przestrzeni nazw, aby rozwiązać niejednoznaczność. Na przykład, jeśli absolutnie nie możesz zmienić nazwy żadnej z
Foo()
klas, możesz użyć ich częściowych przestrzeni nazw:Konkretne powody twojego obecnego projektu:
Zaktualizowałeś swoje pytanie, podając konkretne powody, dla których otrzymałeś projekt zgodnie z tym standardem. Rzućmy na nie okiem i naprawdę zanurkujmy szlakiem króliczka.
"Nieporęczny?" Yyy ... nie. Być może denerwujące. Przeniesienie kilku uncji plastiku w celu przesunięcia wskaźnika na ekranie nie jest uciążliwe . Ale dygresję.
Ten tok rozumowania wydaje się bardziej ukrywaniem niż czymkolwiek innym. Domyślam się, że klasy w aplikacji są słabo nazwane i musisz polegać na przestrzeni nazw, aby uzyskać odpowiednią ilość informacji semantycznych otaczających nazwę klasy.
Nie jest to uzasadnione uzasadnienie dla w pełni kwalifikowanych nazw klas, być może jest to uzasadnione uzasadnienie dla używania częściowo kwalifikowanych nazw klas.
Ta (kontynuowana?) Linia rozumowania potwierdza moje podejrzenie, że klasy są obecnie źle nazwane. Ponownie, posiadanie złych nazw klas nie jest dobrym uzasadnieniem dla wymagania od wszystkiego, aby używać w pełni kwalifikowanej nazwy klasy. Jeśli nazwa klasy jest trudna do zrozumienia, istnieje znacznie więcej błędów niż to, co mogą naprawić w pełni kwalifikowane nazwy klas.
Ze wszystkich powodów ten prawie zmusił mnie do wyplucia drinka. Ale znowu dygresję.
Zastanawiam się, dlaczego zespół często edytuje lub wyświetla kod poza Visual Studio? A teraz patrzymy na uzasadnienie, które całkiem dobrze jest prostopadłe do tego, co mają zapewnić przestrzenie nazw. Jest to argument oparty na oprzyrządowaniu, podczas gdy przestrzenie nazw służą do zapewnienia struktury organizacyjnej kodu.
Wygląda na to, że projekt własny cierpi z powodu złych konwencji nazewnictwa wraz z programistami, którzy nie wykorzystują tego, co może zapewnić narzędzie. Zamiast rozwiązać te rzeczywiste problemy, próbują uderzyć bandażem na jeden z symptomów i wymagają w pełni kwalifikowanych nazw klas. Myślę, że można bezpiecznie zakwalifikować to jako błędne podejście.
Biorąc pod uwagę, że istnieją źle nazwane klasy i przy założeniu, że nie można dokonać refaktoryzacji, poprawną odpowiedzią jest pełne wykorzystanie możliwości Visual Studio IDE. Być może rozważ dodanie wtyczki takiej jak pakiet VS PowerTools. Następnie, kiedy patrzę
AtrociouslyNamedClass()
, mogę kliknąć nazwę klasy, nacisnąć F12 i przejść bezpośrednio do definicji klasy, aby lepiej zrozumieć, co ona próbuje zrobić. Podobnie, mogę kliknąć Shift-F12, aby znaleźć wszystkie miejsca w kodzie, które obecnie cierpią z powodu konieczności użyciaAtrociouslyNamedClass()
.Jeśli chodzi o zewnętrzne obawy związane z oprzyrządowaniem - najlepiej po prostu to zatrzymać. Nie wysyłaj fragmentów wiadomości e-mail w tę iz powrotem, jeśli nie są od razu jasne, do czego się odnoszą. Nie używaj innych narzędzi poza Visual Studio, ponieważ narzędzia te nie mają inteligencji otaczającej kod, którego potrzebuje Twój zespół. Notepad ++ to niesamowite narzędzie, ale nie jest przeznaczone do tego zadania.
Zgadzam się zatem z twoją oceną dotyczącą trzech konkretnych uzasadnień, które zostały przedstawione. To powiedziawszy, myślę, że powiedziano ci: „Mamy podstawowe problemy w tym projekcie, które nie mogą / nie mogą rozwiązać i w ten sposób je„ naprawiliśmy ”. I to oczywiście przemawia do głębszych problemów w zespole, które mogą służyć za czerwone flagi.
źródło
usings
ale nie brzmi to tak, jakby Twój projekt kwalifikował się jako jeden z takich przypadków.Pracowałem w jednej firmie, w której miały wiele klas o tej samej nazwie, ale w różnych bibliotekach klas.
Na przykład,
Można powiedzieć, że jest to zły projekt, ale wiesz, jak te rzeczy rozwijają się organicznie i jaka jest alternatywa - zmień nazwy wszystkich klas, aby uwzględnić przestrzeń nazw? Poważne refaktoryzowanie wszystkiego?
W każdym razie istniało kilka miejsc, w których projekty odwołujące się do wszystkich tych różnych bibliotek musiały używać wielu wersji tej klasy.
Z
using
bezpośrednio na górze był to poważny ból w dupie, ReSharper zrobiłby dziwne rzeczy, aby spróbować, aby działał, przepisującusing
dyrektywy w locie, można dostać klienta, którego nie można obsadzić jako Błędy w stylu klienta i nie wiadomo, który typ był prawidłowy.Mając przynajmniej częściową przestrzeń nazw,
lub
znacznie poprawiło czytelność kodu i wyraźnie wskazało, który obiekt chcesz.
To nie był standard kodowania, nie była pełna przestrzeń nazw i nie była stosowana do wszystkich klas jako standard.
źródło
Nie ma sensu być zbyt gadatliwym ani zbyt krótkim: złoty środek powinien być wystarczająco szczegółowy, aby zapobiec subtelnym błędom, unikając jednocześnie pisania zbyt dużej ilości kodu.
W języku C # przykładem tego są nazwy argumentów. Kilka razy napotkałem problem, w którym spędziłem godziny na szukaniu rozwiązania, a bardziej szczegółowy styl pisania może przede wszystkim zapobiec błędowi. Problem polega na błędzie w kolejności argumentów. Na przykład, czy to ci odpowiada?
Na pierwszy rzut oka wygląda idealnie, ale jest błąd. Podpisy konstruktorów wyjątków to:
Zauważyłeś kolejność argumentów?
Przyjmując bardziej szczegółowy styl, w którym nazwa argumentu jest określana za każdym razem, gdy metoda akceptuje dwa lub więcej argumentów tego samego typu , zapobiegamy ponownemu wystąpieniu błędu, a więc:
jest oczywiście dłuższy, aby pisać, ale powoduje mniej czasu traconego na debugowanie.
Doprowadzony do skrajności, można zmusić do używania nazwanych argumentów wszędzie , w tym w metodach takich jak
doSomething(int, string)
tam, gdzie nie ma sposobu na pomieszanie kolejności parametrów. Prawdopodobnie zaszkodzi to projektowi w dłuższej perspektywie, skutkując znacznie większym kodem bez korzyści zapobiegania opisanemu powyżej błędowi.W twoim przypadku, motywacja za „No
using
zasady” jest to, że powinno to utrudnić korzystanie z niewłaściwego typu, takie jakMyCompany.Something.List<T>
w porównaniuSystem.Collections.Generic.List<T>
.Osobiście unikałbym takiej reguły, ponieważ, według IMHO, koszt trudnego do odczytania kodu znacznie przewyższa korzyść nieznacznie zmniejszonego ryzyka niewłaściwego użycia niewłaściwego typu, ale przynajmniej istnieje uzasadniony powód tej reguły.
źródło
paramName
zInvokerParameterName
atrybutem i emituje ostrzeżenie, jeśli nie ma takiego parametru istnieje.SomeBusiness.Something.DoStuff(string name, string description)
? Żadne narzędzie nie jest wystarczająco inteligentne, aby zrozumieć, co jest nazwą, a co opisem.Przestrzenie nazw nadają kodowi hierarchiczną strukturę, pozwalając na krótsze nazwy.
Jeśli zezwolisz na słowo kluczowe „używanie”, nastąpi ciąg zdarzeń ...
(ponieważ obejmują każdą przestrzeń nazw, jakiej mogliby chcieć)
Aby uniknąć ryzyka, wszyscy zaczynają używać naprawdę długich nazw:
Sytuacja nasila się ...
Widziałem, jak to się dzieje, więc mogę współczuć firmom, które zakazują „używania”.
źródło
using
jest opcją nuklearną. Preferowane są aliasy przestrzeni nazw i częściowa kwalifikacja.Problem
using
polega na tym, że magicznie dodaje do przestrzeni nazw bez wyraźnej deklaracji. Jest to o wiele większy problem dla programisty zajmującego się konserwacją, który napotyka coś takiegoList<>
i bez znajomości domeny, nie wie, którausing
klauzula go wprowadziła.Podobny problem występuje w Javie, jeśli ktoś pisze,
import Java.util.*;
a nieimport Java.util.List;
na przykład; ta ostatnia deklaracja dokumentuje, jaka nazwa została wprowadzona, aby w przypadkuList<>
późniejszego wystąpienia w źródle jej pochodzenie było znane zimport
deklaracji.źródło