Czy używanie nazw parametrów różniących się od nazw typów tylko obudową jest uważane za złą praktykę w języku C #?


43

Widzę pytania podobne do tego w odniesieniu do nazw parametrów, które pasują do właściwości w klasie, ale nie mogę znaleźć niczego dotyczącego używania nazwy parametru, która jest taka sama jak nazwa typu parametru, z wyjątkiem casing w C #. Wydaje się, że nie jest to naruszenie, które mogę znaleźć, ale czy uważa się to za złą praktykę? Na przykład mam następującą metodę

public Range PadRange(Range range) {}

Ta metoda przyjmuje zakres i zwraca nowy zakres z zastosowanym dopełnieniem. Biorąc pod uwagę ogólny kontekst, nie mogę wymyślić bardziej opisowej nazwy parametru. Przypomniała mi się jednak wskazówka, którą wybrałem podczas czytania Code Complete na temat „dystansu psychologicznego”. To mówi

Odległość psychologiczną można zdefiniować jako łatwość różnicowania dwóch elementów ... Podczas debugowania przygotuj się na problemy spowodowane niewystarczającą odległością psychologiczną między podobnymi nazwami zmiennych i między podobnymi nazwami rutynowymi. Podczas konstruowania kodu wybieraj nazwy z dużymi różnicami, aby uniknąć problemu.

Moja sygnatura metody ma wiele „zasięgu”, więc wydaje się, że może to być problem w odniesieniu do tego dystansu psychologicznego. Teraz widzę, że wielu programistów wykonuje następujące czynności

public Range PadRange(Range myRange) {}

Osobiście bardzo nie lubię tej konwencji. Dodanie przedrostka „my” do nazw zmiennych nie zapewnia dodatkowego kontekstu.

Widzę również następujące

public Range PadRange(Range rangeToPad) {}

Podoba mi się to bardziej niż „mój” prefiks, ale nadal nie dbam o to ogólnie. Po prostu wydaje mi się to zbyt szczegółowe i odczytuje niezręcznie jako nazwę zmiennej. Dla mnie zrozumiałe jest, że zakres zostanie uzupełniony z powodu nazwy metody.

Więc przy tym wszystkim, moim przeczuciu jest iść z pierwszym podpisem. Dla mnie to jest czyste. Nie ma potrzeby wymuszania kontekstu, gdy nie jest potrzebny. Ale czy robię sobie lub przyszłym programistom niezadowolenie z tej konwencji? Czy naruszam najlepszą praktykę?


35
Jeśli nie możesz wymyślić bardziej opisowego parametru, Range rangejest w porządku.
Robert Harvey

21
W tej sytuacji IDE pokoloruje „Zasięg” i „Zasięg” inaczej, więc naprawdę łatwo jest zauważyć, że jeden jest typem, a drugi zmienną nazwą.
17 z 26

10
Tak, pamiętam to. Uwzględniono je w wytycznych projektowych. „UWAŻAJ, że właściwość ma taką samą nazwę jak jej typ”. docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Jason Tyler

11
Również dobrze: Range r(przynajmniej dla krótkiej treści metody) i Range toPad.
Bergi,

19
Zawsze uważałem „mój” prefiks za coś, co zostało zrobione w przykładowym kodzie, w którym służy do wskazania czytelnikowi, że nazwa powinna zostać zmieniona na coś innego, w zależności od kontekstu. Nie jest to coś, co powinno skończyć się w prawdziwym kodzie.
kapex

Odpowiedzi:


100

Nie przemyśl tego, Range rangejest w porządku. Używam tego rodzaju nazewnictwa od ponad 15 lat w C #, i prawdopodobnie znacznie dłużej w C ++, i nigdy nie doświadczyłem żadnych prawdziwych wad, wręcz przeciwnie.

Oczywiście, jeśli masz różne zmienne lokalne w tym samym zakresie, wszystkie tego samego typu, prawdopodobnie pomoże to zainwestować trochę wysiłku umysłowego w ich prawidłowe rozróżnienie.


6
Kolejnym wyjątkiem, który dodam, jest to, że instancja wykonuje na nim określone działanie. Jest trochę miejsca na bardziej opisowe wyjaśnienie na przykład, dlaczego parametr jest potrzebny. Wack (Bozo bozoToBeWacked) Tym bardziej, jeśli parametr jest opcjonalny i opisuje, co oznacza obiekt w tym scenariuszu / co na niego wpłynie. Moja ogólna zasada, jeśli nie jest oczywiste, nie patrząc na kod, co robi parametr, to potrzebuje lepszej nazwy i / lub komentarzy.
Mike

17
Uważałbym Wack(Bozo bozoToBeWacked)za przykład nadmiarowości w nazwie zmiennej, która jest wyrażona w sposób obfity przez samą metodę (a zatem niepożądana w pierwotnym pytaniu). Wack(Person bozo)jest jednak bardziej wartościowa semantycznie, ponieważ implikuje, że oczekuje się, że tylko bozo zostaną wyrzucone.
Miral,

2
W przypadku, o którym wspominasz w drugim akapicie, często zmieniam nazwę parametru na coś w rodzaju initialRange. Nadal jest bardzo ogólny, ale nie ma prawie tego samego poziomu niesmaku jak myRange.
Jaquez,

@Miral: Staje się bardziej odpowiedni w takich przypadkach jak Punch(Bozo punchingBozo, Bozo bozoToBePunched). Szczegółowe nazewnictwo jest bardziej odpowiednie, gdy trzeba rozróżnić wiele rzeczy (które są semantycznie opisane za pomocą tych samych słów). Sugestia OP Range rangeToPadnie jest konieczna w jego przykładzie metody jednoparametrowej, ale może być niezwykle konieczna dla metody, która przyjmuje kilka Rangeobiektów.
Flater

7
@Flater wykonałby Punch(Bozo source, Bozo target)zadanie
Thomas Ayoub,

17

Robię to cały czas, daje mi to świetne zdanie. Jeśli jest to argument przekazany konstruktorowi, który należy przypisać do elementu członkowskiego, mój element członkowski również otrzymałby nazwę range, a przypisanie to

this.range = range;

I zazwyczaj miałbym właściwość o nazwie Range.

Wszystkie są takie same, różnią się tylko kontekstem, więc utrzymanie jednego imienia ma sens, a będziesz musiał zapamiętać tylko jedno imię. To jedno, różnice są czysto techniczne.

Powinieneś być surowy wobec w pełni kwalifikujących się członków z „tym”. choć właśnie po to jest StyleCop.

Notatka boczna StyleCop

Kontrowersje gwarantowane!

Dla tych, którzy opowiadają się przeciwko używaniu „tego”: widziałem _, m, m_ i tylko nic. Sam język oferuje nam całkowicie jasny, jednoznaczny, powszechnie rozpoznawalny sposób wskazywania, że ​​mamy do czynienia z członkiem klasy. Dlaczego, u licha, chciałbyś wymyślić własną drogę, która okalecza i tak już doskonałe nazwy?

Jedyny powód, dla którego mogę o tym pomyśleć, że jest to nawyk spuścizny z epoki C, kiedy to miało sens, ponieważ nie było innego wyjścia.

„To więcej postaci!” Poważnie? „Czas kompilacji gwałtownie wzrośnie!” Poważnie? „Będę musiał podnieść mój pinky podczas pisania!”. Jakby czas pisania miał jakieś znaczenie w całkowitym czasie programowania.

Zdaję sobie sprawę, że każdy styl inny niż ten, do którego jesteś przyzwyczajony, wzbudzi sprzeciw. Jednak konsekwentne korzystanie z tego jest trudne. Oto, jak to działa dla mnie: zanim wypchnę nowy plik kodu, uruchamiam StyleCop i znajdzie on liczbę członków, którzy nie mają kwalifikatorów „tego”. Umieszczam „to”. w schowku, prowadzony przez członków i wstaw. Bez żadnego wysiłku.

StyleCop robi o wiele więcej (haha). Jest tak wiele sposobów, w jakie programista może (tylko biorąc pod uwagę formatowanie kodu) udaremnić prace konserwacyjne swojego następcy. StyleCop zapobiega większości z nich. To jest nieocenione.

Jeśli jesteś nowy: zazwyczaj narzekasz przez tydzień lub dwa, a potem pokochasz.


19
Powinieneś być jednak surowy wobec w pełni kwalifikujących się członków z„ tym ”., „ -1. Nie używaj, thischyba że jest to konieczne. W przeciwnym razie to tylko hałas. Użyj _rangedla pola i thisnigdy nie jest potrzebne, z wyjątkiem metod rozszerzenia.
David Arno,

12
Zgadzam się z @DavidArno. „to” to po prostu czysty hałas. „Zakres” jest właściwością, „_zakres” jest polem, a „zasięg” jest parametrem.
17 z 26

8
@David Jeśli zmienna jest członkiem klasy, JEST ona niezbędna i bije dowolny dowolny przedrostek sygnalizujący, że patrzysz na członka klasy, a nie na argument lub zmienną lokalną.
Martin Maat,

6
Moje IDE strzelało kulami ognia w momencie, gdy przypisywałem sobie zmienną.
Koekje

21
@DavidArno Zastanów się, dlaczego „hałas” _jest lepszy niż hałas this.? Twierdziłbym, że jedno ma znaczenie narzucone przez język (i zwykle ma podświetlanie składni), podczas gdy drugie nie.
Clint

9

Moje wskazówki dotyczące metod nazewnictwa, parametrów i zmiennych są dość proste:

  1. Jeśli nazwa zawiera typ, który jest przekazywany lub zwracany, robisz to źle.
  2. Nazwij rzeczy według tego, do czego są przeznaczone, a nie czym są.
  3. Zawsze pamiętaj, że kod jest czytany więcej niż jest napisany.

Zatem moim zdaniem optymalną sygnaturą metody byłoby:

Range Pad(Range toPad)

Skrócenie nazwy metody jest oczywiste.

Nazwa parametru toPadnatychmiast informuje czytelnika, że ​​ten parametr prawdopodobnie zostanie zmodyfikowany w miejscu poprzez wypełnienie, a następnie zwrócenie. Przeciwnie, nie można przyjąć żadnych założeń dotyczących zmiennej o nazwie range.

Ponadto, w rzeczywistej treści metody, wszelkie inne Rangezmienne, które są wprowadzane, powinny (powinny) być nazwane według ich zamiarów, więc możesz mieć paddedi unpadded... toPadjest zgodny z tymi konwencjami nazewnictwa, ale rangepo prostu wystaje i nie żeluje.


3
padded/ unpaddedbrzmi dobrze dla lokalnych niezmiennych zmiennych. Ale jeśli istnieje zmienny toPadparametr, to po zakończeniu wypełniania nazwa toPadjuż nie pasuje (chyba że wynik zostanie natychmiast zwrócony). Range rangeW takich przypadkach wolałbym się trzymać .
kapex

@Kapep nazwałbym to po prostu result. Zostanie zmodyfikowany i zwrócony . To drugie wynika z nazwy, a drugie wynika z tego, że zwrócenie niemodyfikowanego argumentu nie ma sensu.
maaartinus,

Z podpisu Padmetoda zwraca a Range. To dla mnie oznacza, że ​​ten, który przekazałem, zostanie zachowany, a nie zmodyfikowany w miejscu, a nowy, wyściełany Rangezostanie zwrócony. .
Aaron M. Eshbach,

1
Nie jestem pewien, co sądzić o twoich radach. Pad(toPad)czuje się trochę źle IMHO. Dobrze bronisz swojego punktu widzenia. Dostajesz ode mnie +0! :)
Eric Duminil

W pytaniu stwierdza, że ​​„zwraca nowy zakres z zastosowanym dopełnieniem”. Zgadzam się z nazywania tego, co myślisz, że scenariusz jest, ale za rzeczywiste pytania pójdę na coś takiego zasięgiem CreateRangeWithPadding (źródło Range)
Richard Willis

3

Kluczowym pytaniem, które należy sobie zadać, jest nazywanie elementów kodu (typów, zmiennych, funkcji itp.)

Jeśli zrobię literówkę, czy kompilator ją dla mnie znajdzie?

Najgorszy rodzaj błędu opartego na literówkach to taki, w którym kod się kompiluje i działa, ale daje inne zachowanie niż się spodziewano z powodów, które są subtelne. A ponieważ jest to spowodowane literówką, zwykle bardzo trudno jest zobaczyć, kiedy sprawdzasz kod. Jeśli literówka zatrzyma kompilację kodu, kompilator oznaczy wiersz powodując problem, a ty możesz łatwo go znaleźć i naprawić.

W sytuacji, gdy typ i zmienna różnią się jedynie wielkością liter, zawsze tak będzie. (Lub prawie zawsze - przy wystarczającym wysiłku, jestem pewien, że mógłbyś sprawić, by działało, ale naprawdę musisz spróbować.) Myślę więc, że tam jesteś OK.

Trzeba by się martwić, gdyby w bieżącym zakresie były dwie zmienne, metody, funkcje lub właściwości o nazwie rangei Range. W takim przypadku kompilator prawdopodobnie będzie niech to przez, i masz zamiar uzyskać nieoczekiwane zachowanie w czasie wykonywania. Zauważ, że to dwa każdy z tych typów elementów kodu, nie tylko „dwie zmienne” lub „dwie funkcje” - wszystkie te mogą być niejawnie oddanych do siebie, co powoduje rzezi, gdy skończy. Możesz otrzymywać ostrzeżenia, ale nie możesz zagwarantować nic więcej. Podobne problemy występują, jeśli zgłoszono dwa typy nazwane rangei Range.

Należy również pamiętać, że to samo dotyczy węgierskiego stylu notacji , w którym nazwy są poprzedzone jednym lub kilkoma znakami, aby powiedzieć coś więcej na temat tego, co to jest. Jeśli masz zmienną o nazwie Rangei wskaźnik do niej o nazwie PRange, łatwo na przykład przypadkowo pominąć P. C # powinien to złapać, ale C i C ++ dają tylko ostrzeżenie. Lub, co bardziej niepokojące, załóżmy, że masz podwójną wersję o nazwie DRangei próbkujesz ją do wersji o nazwie float FRange. Użyj jednego pływaka przez przypadek (co jest proste, ponieważ klucze sąsiadują na klawiaturze) i kod będzie rodzaj z pracy, ale to się przewrócić w dziwnych i nieprzewidywalny sposób, gdy proces skończy się rozdzielczością i niedomiarów.

Nie jesteśmy już w czasach, w których mieliśmy ograniczenia nazewnictwa wynoszące 8 znaków lub 16 znaków lub dowolny dowolny limit. Czasami słyszałem, jak nowicjusze narzekają na dłuższe nazwy zmiennych, co powoduje, że kodowanie trwa dłużej. Jednak tylko nowicjusze narzekają na to. Poważni koderzy wiedzą, że to, co naprawdę wymaga czasu, to znajdowanie niejasnych błędów - a zły wybór nazewnictwa to klasyczny sposób, aby wpaść w tę konkretną dziurę.


Uwaga dla czytelników - w języku C # ludzie powinni naprawdę unikać notacji węgierskiej. Chociaż był użyteczny w starszych czasach, kiedy podświetlanie składni nie było niczym lub było ograniczone, obecnie tak naprawdę nie pomaga.
T. Sar - Przywróć Monikę

@ T.Sar Nawet w czasach nienawidziłem tego z pasją! Jak mówisz, lepsze IDE rozwiązały problemy, do których były skierowane, ale wciąż pojawiają się tak często. Nadal go zobaczysz, jeśli chcesz na przykład porozmawiać z interfejsem API systemu Windows z powodów historycznych. Nie chciałem całkowicie krytykować preferowanych stylów ludzi, jeśli naprawdę im się podobają, ale chciałem użyć tego jako haka do pokazania, że ​​wielkie / małe litery nie są jedynym sposobem na zepsucie nazewnictwa.
Graham,

Wiem, że nie proponujesz użycia notacji węgierskiej, ale jestem również świadomy, że młodzi twórcy mają ogromną słabość do rzeczy o fajnych nazwach. Będąc w stanie powiedzieć: „Mój kod jest napisany w tym super tajnym stylu kodowania ninja - notacja węgierska!” młodszym umysłom może brzmieć nieodparcie chłodno. Widziałem zbyt wielu programistów padających ofiarą szumu fajnych słów ... Notacja węgierska to ból, który daje formę kodu źródłowego xX
T. Sar - Przywróć Monikę

@ T.Sar Prawda. „Ci, którzy nie pamiętają przeszłości, skazani są na jej powtórzenie” i tak dalej. : /
Graham,

1
Czy mówimy o oryginalnej notacji węgierskiej lub o tym, jak została rażąco błędnie zinterpretowana przez Microsoft (w pobliżu „autorzy dokumentacji w zespole systemu Windows nieumyślnie wymyślili coś, co stało się znane jako węgierski system”, a także w wywiadzie dla Joela Spolsky'ego autorstwa Leo Laporte w odcinku Triangulacja 277, 12.12.2016, 04 minut 00 sekund - 06 minut 35 sekund )?
Peter Mortensen

1

Jedna anegdota, którą chciałbym dodać, chociaż Range rangejest to syntaktycznie legalne, może utrudnić debugowanie lub refaktoryzację. Szukasz tej jednej zmiennej o nazwie „zakres” w pliku z dużą ilością zmiennych typu Range? Możesz później wykonać więcej pracy w wyniku wyboru nazwy.

Jest to jednak w dużej mierze zależne od kontekstu. Jeśli jest to plik 30-liniowy, moje wypowiedzi tak naprawdę nie wchodzą w grę.


7
Większość osób korzysta z narzędzi rozróżniających typy i parametry lub zmienne do programowania systemu Windows. To, co opisujesz, przypomina mi stare dobre grepowe dni na Uniksie.
Frank Hileman,

1
@FrankHileman Może cię to zaskoczyć, ale Unix wciąż żyje, a grep jest nadal używany (: D). Ponieważ w grep rozróżniana jest wielkość liter, wspomniany problem po prostu nie istnieje. Jednak nawet my, uzależnieni od terminali, nienawidzący okien, rzadko używamy grep dla kodu źródłowego, ponieważ IDE jest znacznie lepszy w typowych wyszukiwaniach.
maaartinus,

Myślę, że zgadzamy się z tym, że platforma nie jest celem. grepjest doskonałym narzędziem, ale nie jest narzędziem refaktoryzującym. Narzędzia refaktoryzacji istnieją na każdej platformie programistycznej, z której korzystałem. (OS X, Ubuntu, Windows).
Eric Wilson,

@EricWilson Kiedyś grep i sed były jedynymi narzędziami refaktoryzującymi w Uniksie.
Frank Hileman,

@FrankHileman To, że coś jest używane jako narzędzie do refaktoryzacji, nie oznacza, że ​​tak jest. Mogę refaktoryzować w notatniku, ale to nie jest więcej niż edytor tekstu.
Eric Wilson,

1

Myślę, że możesz używać dni Range rangedzisiejszych z jednego powodu: podświetlania składni. Nowoczesne IDE zwykle podkreślają nazwy typów i nazwy parametrów w różnych kolorach . Również typ i zmienna mają znaczną „logiczną odległość”, której nie można łatwo pomylić.

Jeśli tak nie jest, rozważę inną nazwę lub spróbuję włączyć wtyczkę / rozszerzenie, które może to wyróżniać składnię.


0

Gdy funkcja jest ogólna, to znaczy, że parametry będą ogólne, a zatem powinny mieć nazwy ogólne.

Nie to, co mówisz, ale widziałem funkcje, które wykonują funkcje ogólne, które mają nazwy parametrów, które są myląco specyficzne. Lubić

public String removeNonDigits(String phoneNumber)

Nazwa funkcji brzmi bardzo ogólnikowo, tak jakby można ją było zastosować do wielu ciągów w wielu sytuacjach. Ale nazwa parametru jest dziwnie specyficzna, co sprawia, że ​​zastanawiam się, czy nazwa funkcji wprowadza w błąd, czy ... co?

Więc na pewno zamiast powiedzieć Range Range, możesz powiedzieć Range RangeToPad. Ale jakie informacje to dodaje? Oczywiście to zakres pad. Co jeszcze by to było?

Dodanie dowolnego przedrostka „my” lub „m_” lub cokolwiek innego, przekazuje czytelnikowi zero dodatkowych informacji. Kiedy korzystałem z języków, w których kompilator nie pozwala na to, aby nazwa zmiennej była taka sama jak nazwa typu - z rozróżnianiem wielkości liter lub bez - czasami umieszczam prefiks lub sufiks, aby kompilować go . Ale to tylko po to, by zaspokoić kompilator. Można argumentować, że nawet jeśli kompilator jest w stanie odróżnić, ułatwia to ludzkiemu czytelnikowi rozróżnienie. Ale wow, w Javie napisałem oświadczenia takie jak „Klient klient = nowy Klient ();” miliard razy i nigdy nie pomyliłem się. (Zawsze uważałem, że jest to trochę zbędne i raczej podoba mi się to w VB, możesz po prostu powiedzieć „ciemny klient jako nowy klient” i nie musisz podawać nazwy klasy dwa razy).

W przypadku, gdy DOKŁADNIE sprzeciwiam się nazwom ogólnym, to w tej samej funkcji występują dwa lub więcej wystąpień tego samego typu. SPECJALNIE parametry. Lubić:

public Range pad(Range range1, Range range2)

Jaka jest różnica między zakresem 1 a zakresem 2? Jak mogę to wiedzieć? Jeśli jest to coś, gdzie naprawdę są dwie ogólne i wymienne wartości, dobrze, na przykład

public boolean overlap(Range range1, Range range2)

Spodziewałbym się, że zwróci wartość true, jeśli zakresy będą się nakładać, a false, jeśli nie, więc są ogólne i wymienne.

Ale jeśli są różne, daj mi wskazówkę, jak się różnią! Niedawno pracowałem nad programem, który miał klasę „Place” do przechowywania danych o miejscach geograficznych i ze zmiennymi tego typu o nazwie „p”, „place”, „place2”, „myPlace” itp. Wow, te nazwy naprawdę pomagają mi ustalić, który jest który.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.