Чи використання імен параметрів, які відрізняються від імен типів лише за допомогою корпусу, вважається поганою практикою в C #?


43

Я бачу подібні до цього питання щодо імен параметрів, які відповідають властивостям класу, але я не можу знайти нічого щодо використання імені параметра, яке є таким же, як назва типу параметра, за винятком корпусу в C #. Я не можу виявити порушення, але чи вважається це поганою практикою? Наприклад, у мене є такий метод

public Range PadRange(Range range) {}

Цей метод займає діапазон і повертає новий діапазон, до якого було застосовано деяку підкладку. Отже, враховуючи загальний контекст, я не можу придумати більш описову назву параметра. Однак мені нагадується підказка, яку я зібрав, читаючи Code Complete про "психологічну дистанцію". Він говорить

Психологічну відстань можна визначити як легкість, в якій можна розділити два елементи ... Під час налагодження будьте готові до проблем, спричинених недостатньою психологічною дистанцією між подібними назвами змінних та між подібними рутинними іменами. Під час створення коду вибирайте імена з великими відмінностями, щоб уникнути проблеми.

У моєму підписі методу багато "діапазону" відбувається, тому, схоже, це може бути проблемою щодо цієї психологічної дистанції. Зараз я бачу, що багато розробників роблять наступне

public Range PadRange(Range myRange) {}

Я особисто сильно нехтую цією конвенцією. Додавання префікса "мій" до імен змінних не надає додаткового контексту.

Я також бачу таке

public Range PadRange(Range rangeToPad) {}

Мені це подобається краще, ніж "моя" префіксація, але все-таки це все одно не стосується. Він просто відчуває себе надмірно багатослівним і незграбно читає ім'я змінної. Мені зрозуміло, що діапазон буде залитий через назву методу.

Тож з усім цим викладеним, моя кишка повинна йти з першим підписом. Для мене це чисто. Не потрібно форсувати контекст, коли це не потрібно. Але чи я роблю собі чи майбутнім розробникам сумніви щодо цієї конвенції? Я порушую найкращу практику?


35
Якщо ви не можете придумати більш описовий параметр, Range rangeце добре.
Роберт Харві

21
У цій ситуації IDE буде забарвлювати "Діапазон" та "Діапазон" по-різному, тому дуже легко зрозуміти, що один тип, а ім'я змінної.
17 з 26

10
Так, я це пригадую. Це в їх керівництві щодо дизайну як врахування. "ВІДКЛЮЧИТИ надання властивості такою ж назвою, як і її тип." docs.microsoft.com/en-us/dotnet/standard/design-guidelines/…
Джейсон Тайлер

11
Також добре: Range r(принаймні, для короткого методу) та Range toPad.
Бергі

19
Я завжди розглядав префікс "мій" як те, що робиться в прикладі коду, де його вказують читачеві, що ім'я слід змінити на щось інше залежно від контексту. Це не те, що насправді повинно опинитися в будь-якому реальному коді.
капекс

Відповіді:


100

Не передумуйте це, Range rangeдобре. Я використовую такий тип імен більше 15 років у C #, і, мабуть, набагато довше в C ++, і ніколи не відчував реальних недоліків у ньому, навпаки.

Звичайно, коли у вас є різні локальні змінні в одному і тому ж просторі, все одного типу, це, ймовірно, допоможе вкласти певні розумові зусилля, щоб правильно їх розрізнити.


6
Ще одне виключення, яке я додам, - це коли екземпляр робить певну дію над ним. Існує трохи місця для того, щоб бути більш описовим, чому, наприклад, потрібен параметр. Wack (Bozo bozoToBeWacked) Тим більше, що параметр необов'язковий і описує, що означає об'єкт у цьому сценарії / що він вплине. Моє правило, якщо це не очевидно, не дивлячись на код, що робить параметр, тоді йому потрібно краще ім'я та / або коментарі.
Майк

17
Я б розглядав Wack(Bozo bozoToBeWacked)як приклад надмірності імені змінної, яка чітко виражається самим методом (і, таким чином, небажана для початкового питання). Wack(Person bozo)однак є більш семантично цінним, оскільки це означає, що очікується, що він може пробудити лише бозо.
Міраль

2
У випадку, коли ви згадуєте у другому абзаці, я часто перейменую параметр на щось подібне initialRange. Він все ще дуже загальний, але не має майже такого ж рівня неприємності, як myRange.
Якес

@Miral: Це стає більш актуальним у таких випадках, як Punch(Bozo punchingBozo, Bozo bozoToBePunched). Детальне називання є більш доречним, коли вам доведеться розрізняти кілька речей (які семантично описуються майже однаковими словами). Пропозиція ОП Range rangeToPadне є необхідною у прикладі його методу з одним параметром, але може бути неймовірно необхідною для методу, що містить декілька Rangeоб'єктів.
Флатер

7
@Flater зробив Punch(Bozo source, Bozo target)би цю роботу
Thomas Ayoub

17

Я роблю це постійно, це дає мені великий розум. Якщо це аргумент, переданий конструктору, якого потрібно призначити члену, мій член буде також названий діапазоном, а призначення буде

this.range = range;

І, як правило, у мене є властивість з назвою Range.

Вони все одне і те ж, лише відрізняються за контекстом, тому є сенс зберегти одне ім’я, і вам доведеться запам'ятати лише одне ім’я. Одна справа, відмінності суто технічні.

Ви повинні бути суворими з повністю кваліфікованими членами з "цим". хоча, але саме для цього StyleCop.

Сторона примітки StyleCop

Суперечки гарантовані!

Тим, хто виступає проти використання "цього": я бачив _, m, m_ і просто нічого. Сама мова пропонує нам ідеально чіткий, однозначний загальновизнаний спосіб вказувати, що ми маємо справу з членом класу. Чому б на землі ви хотіли скласти свій спосіб, який змушує вже досконалі імена?

Єдина причина, про яку я можу подумати про те, що це спадщина з епохи С, коли насправді це мало сенс робити, оскільки іншого способу не було.

"Це більше символів!" Серйозно? "Час компіляції злетить!" Серйозно? "Мені доведеться підняти рожевий під час набору тексту!". Ніби час набору тексту мав якесь значення в загальному часі розробки.

Я усвідомлюю, що будь-який стиль, відмінний від того, до якого ви звикли, викликає деяку опозицію. Але з використанням цього послідовно важко посперечатися. Ось як це працює для мене: Перш ніж натиснути новий файл коду, я запускаю StyleCop, і в ньому знайдуться кількість членів, яким не вистачає "цього". Я ставлю "це". в буфер обміну, запускається членами та вставляє. Немає зусиль.

StyleCop робить набагато більше, ніж це (ха-ха). Існує так багато способів, що розробник може (лише враховуючи форматування коду) зірвати роботу з обслуговування свого наступника. StyleCop заважає більшості з них. Це неоціненний.

Якщо ви новачок у ньому: це зазвичай змушує вас бурчати протягом тижня-двох, і тоді вам сподобається.


19
" Ви повинні бути суворими з повністю кваліфікованими членами з" цим ". Хоча, " -1. Не використовуйте, thisза винятком випадків першої необхідності. Це просто шум інакше. Використовуйте _rangeдля поля і thisніколи не потрібно, крім методів розширення.
Девід Арно

12
Я погоджуюся з @DavidArno. "це" - просто чистий шум. 'Range' - це властивість, '_range' - поле, а 'range' - параметр.
17 з 26

8
@David Якщо змінна є членом класу, вона є важливою та побиває будь-який довільний префікс, щоб сигналізувати, що ви шукаєте члена класу, а не аргументу чи локальної змінної.
Мартін Мейт

6
Мій IDE стріляв би з вогневих кульок другий, я призначив би змінну собі.
Koekje

21
@DavidArno Care пояснить, чому "шум" _кращий перед шумом this.? Я можу стверджувати, що одне має значення, накладене мовою (і, як правило, мають підкреслення синтаксису), а інше - ні.
Клінт

9

Моє самонавчання щодо методів іменування, параметрів та змінних досить просте:

  1. Якщо ім’я містить тип, який передається або повертається, ви робите це неправильно.
  2. Назвіть речі за тим, що вони призначені, а не тим, якими вони є.
  3. Завжди пам’ятайте, що код читається більше, ніж написано.

Таким чином, оптимальним підписом методу, на мою думку, було б:

Range Pad(Range toPad)

Скорочення назви методу не є зрозумілим.

Назва параметра toPadодразу повідомляє читачеві, що цей параметр, ймовірно, буде змінено на місці, замістивши його, потім повернувшись. На відміну від цього, жодних припущень щодо змінної, названої не можна робити range.

Крім того, у фактичному складі методу будь-які інші Rangeзмінні, що вводяться, повинні були бути названі за їх наміром, тож ви можете мати paddedі unpadded... toPadвідповідати цим умовам іменування, але rangeпросто стирчить і не гелірує.


3
padded/ unpaddedзвучить добре для локальних змінних змінних. Але якщо є toPadпараметр, що toPadзмінюється , після закінчення прокладки назва більше не підходить (якщо результат не буде повернутий негайно). Я б скоріше дотримувався Range rangeцих випадків.
капекс

@Kapep Я б назвав це просто result. Він змінюється і повертається . Останнє зрозуміло з назви, а перший випливає, оскільки повертати немодифікований аргумент не має сенсу.
maaartinus

З підпису Padметод повертає a Range. Це, як на мене, означає, що той, через який я пройшов, буде збережений, а не змінений на місці, і Rangeбуде повернуто нове, підкладене . .
Аарон М. Ешбах

1
Я не впевнений, що думати про вашу пораду. Pad(toPad)відчуває себе неправильно ІМХО. Хоча ви добре відстоюєте свою точку зору. Ви отримуєте від мене +0! :)
Ерік Думініл

У запитанні йдеться про те, що він "повертає новий діапазон, у якому було застосовано деяку підкладку". Я погоджуюся з вашим найменуванням того, що, на вашу думку, є сценарій, але для актуального питання я б підказав щось на зразок Range CreateRangeWithPadding (джерело діапазону)
Річард Вілліс

3

Для найменування елементів коду (типи, змінні, функції, що завгодно) ключовим питанням, яке слід задати себе, є

Якщо я зроблю машинопис, чи знайде його компілятор?

Найгірший вид помилки на основі друку - це той, де код збирається та працює, але дає іншу поведінку від очікуваної, з тонких причин. А оскільки це пов’язано з помилкою друку, зазвичай це дуже важко помітити, коли ви перевіряєте код. Якщо помилка друку зупинить компіляцію коду, компілятор позначить рядок, що викликає проблему, і ви можете легко знайти та виправити її.

Для вашої ситуації, коли тип і змінна різняться лише за великої літери, це завжди буде так. (Або майже завжди - маючи достатньо зусиль, я впевнений, що ви могли б змусити його працювати, але вам доведеться по-справжньому спробувати.) Тому я думаю, що ви там все в порядку.

Там, де вам би потрібно було занепокоєти, було б, якщо існували дві змінні, методи, функції або властивості в поточній області, що називається rangeі Range. У цьому випадку компілятор, ймовірно , пропустить це, і ви отримаєте несподівану поведінку під час виконання. Зауважте, що це два з будь-якого з цих типів кодового елемента, а не лише "дві змінні" або "дві функції" - все це може бути неявно передано одна одній, з отриманою в результаті хитрістю, коли вона працює. Ви можете отримати попередження, але ви нічого не можете гарантувати більше. У вас є подібні проблеми, якщо у вас було оголошено два типи виклику rangeта Range.

Також зауважте, те саме стосується угорського стилю позначень , де імена мають префікс одного чи декількох символів, щоб сказати щось більше про те, що воно є. Якщо у вас є названа змінна Rangeі вказівник на неї викликається PRange, її легко випадково пропустити P, наприклад. C # має це впізнати, але C та C ++ лише попередить вас. Або, що більш тривожно, припустімо, що у вас є подвійна версія, яку DRangeви називаєте, і ви перепробовуєте її до плаваючої версії під назвою FRange. Використовуйте поплавок один випадково (що легко , так як ключі знаходяться поруч на клавіатурі) і ваш код буде вид роботи, але вона буде падати в дивних і непередбачувано , коли процес закінчується дозволом і втрати значущості.

Ми вже не в дні, коли ми мали обмеження іменування до 8 символів, або 16 символів, або будь-яка довільна межа. Я іноді чув, як новачки скаржаться на більш довгі імена змінних, що змушують кодування тривати довше. На це скаржиться лише колись новачок. Серйозні кодери знають, що дійсно потрібен час - це з'ясування незрозумілих помилок - а поганий вибір імен - це класичний спосіб опуститись у цю конкретну яму.


Лише примітка для читачів - для C # люди повинні справді уникати угорських позначень. Хоча це було корисно і в більш давні часи, коли виділення синтаксису не було річчю або було обмежене, але сьогодні воно справді не допомагає.
Т. Сар - Відновлення Моніки

@ T.Sar Ще в той день я ненавиджу це з пристрастю! Як ви кажете, кращі ІДЕ вирішили проблеми, на які вона була спрямована, але вона все ще виникає так часто. Ви все одно побачите це, якщо вам потрібно поговорити з API Windows, наприклад, з історичних причин. Я не хотів повністю базувати вподобані стилі людей, якщо їм це дуже подобається, але я хотів використовувати його як гачок для показу, що верхній / нижній регістр - не єдиний спосіб, коли можна викрутити іменування.
Грем

Я знаю, що ви не пропонуєте використання угорської нотації, але я також усвідомлюю, що молоді дияволи мають величезну слабкість до речей з класними іменами. Вміючи сказати "Мій код написаний у цьому супер секретному стилі кодування ніндзя - угорська нотація!" може здатися непереборно здоровим для молодих розумів. Я бачив, як занадто багато дияволів стають здобиччю галасу прохолодних слів ... Угорська нотація - це біль, що надає форму вихідного коду xX
Т. Сар - Відновлення Моніки

@ T.Sar Вірно. «Ті, хто не пам’ятає минулого, приречені повторити це» і все таке. : /
Грем

1
Ми говоримо про оригінальну угорську нотацію або про те, як це було грубо неправильно трактовано Microsoft (поруч із "авторами документації в команді Windows ненавмисно винайдено те, що стало відомим як Система Угорська", а також в інтерв'ю Джоела Спольського Лео Лапорте за епізодом "Триангуляція" 277, 2016-12-12, 04 хв 00 сек - 06 хв 35 сек )?
Пітер Мортенсен

1

Я хотів би додати один анекдот, хоча Range rangeце синтаксично легально, але він може зробити складнішим налагодження чи рефактор. Шукаєте ту змінну з назвою "діапазон" у файлі з великою кількістю змінних типу Range? Пізніше ви можете зробити більше роботи в результаті цього вибору імен.

Це багато в чому залежить від контексту. Якщо це 30-ти рядковий файл, мої заяви насправді не вступають у дію.


7
Більшість людей використовують інструменти, що розрізняють типи та параметри чи змінні для розробки Windows. Те, що ви описуєте, нагадує мені про старі добрі греп-дні на Unix.
Френк Хілеман

1
@FrankHileman Це може вас здивувати, але Unix все ще живий і греп все ще використовується (: D). Оскільки grep за замовчуванням залежить від регістру, згадана проблема просто не існує. Однак навіть ми, терміново залежні від Windows, рідко використовуємо grep для вихідного коду, оскільки IDE набагато краще при загальних пошукових запитах.
maaartinus

Я думаю, що ми згодні з тим, що платформа не в цьому суть. grepце чудовий інструмент, але це не інструмент рефакторингу. І інструменти рефакторингу існують на кожній платформі розробки, яку я використовував. (OS X, Ubuntu, Windows).
Ерік Вілсон

@EricWilson У свій час, grep і sed були єдиними інструментами рефакторингу на unix.
Френк Хілеман

@FrankHileman Тільки тому, що щось використовується як інструмент рефакторингу, це не означає, що воно є. Я можу переробляти в блокноті, але це не робить його більше ніж текстовим редактором.
Ерік Вілсон

1

Я думаю, що ви можете використовувати Range rangeсьогоднішній день з однієї причини: підсвічування синтаксису. Сучасні IDE зазвичай виділяють назви типів та назви параметрів різними кольорами . Також тип і змінна мають значну "логічну відстань", яку не можна легко сплутати.

Якби це не так, я б розглядав інше ім’я або намагався ввімкнути плагін / розширення, яке може зробити це підсвічування синтаксису.


0

Коли функція є загальною, то, очевидно, параметри будуть загальними, і тому вони повинні мати загальні назви.

Не те, що ви говорите, але я бачив функції, які виконують загальну функцію, мають імена параметрів, що вводять в оману конкретно. Подібно до

public String removeNonDigits(String phoneNumber)

Назва функції звучить дуже загально, тому що це може застосовуватися до багатьох рядків у багатьох ситуаціях. Але ім'я параметра є дивно конкретним, що змушує мене замислитися, чи ім'я функції вводить в оману, або ... що?

Тож впевнено, замість того, щоб сказати діапазон діапазону, можна сказати діапазон діапазонуToPad. Але яка інформація додає це? Звичайно, це діапазон до колодки. Що ще було б?

Додаючи якийсь довільний префікс, "мій" або "m_" або будь-який інший, передає читачу нульову додаткову інформацію. Коли я використовував мови, де компілятор не дозволяє імені змінної бути таким самим, як ім'я типу - з чутливістю до регістру чи без нього, я іноді ставлю префікс або суфікс, просто щоб змусити його компілювати . Але це просто для задоволення компілятора. Можна стверджувати, що навіть якщо компілятор може розрізнити, це полегшує людському читачеві розрізнення. Але ось так, на Java я написав заяви на зразок "Клієнт-клієнт = новий Клієнт ();" мільярд разів, і я ніколи не вважав це заплутаним. (Я завжди вважав це трохи зайвим, і мені більше подобається, що в VB ви можете просто сказати "тьмяний клієнт як новий клієнт", і вам не потрібно вказувати назву класу двічі.)

Там, де Я НЕ сильно заперечую проти загальних імен, коли в одній і тій же функції є два або більше екземплярів одного типу. ОСОБЛИВО параметри. Подібно до:

public Range pad(Range range1, Range range2)

Яка різниця між range1 та range2? Як я повинен знати? Якщо це щось там, де вони справді є двома загальними і взаємозамінними значеннями, добре, як

public boolean overlap(Range range1, Range range2)

Я б очікував, що повернеться істинним, якщо діапазони перекриваються і помилковими, якщо вони не є, тому вони є загальними та взаємозамінними.

Але якщо вони різні, дайте зрозуміти, чим вони відрізняються! Нещодавно я працював над програмою, в якій був клас "Місце" для зберігання даних про географічні місця та зі змінними цього типу з назвою "p", "place", "place2", "myPlace" тощо. Нічого собі, ці імена дійсно допомагають мені визначити, що це таке.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.