Один клас на правило правила у .NET? [зачинено]


185

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

Ще один аргумент, який я чую весь час, це "Навіть Microsoft цього не робить, то чому ми повинні?"

Який загальний консенсус щодо цього? Чи є випадки, коли цього слід уникати?


1
можливий дублікат класів C # в окремих файлах?

Відповіді:


176

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


4
Більше класів в одному файлі збільшує різницю між пов'язаними класами лише в одній операції.
Лука

3
Належні глядачі різниці дозволяють переглядати всі відмінності одного фіксатора.
Дікам

44
Я не зовсім впевнений, наскільки саме ця відповідь відповідає на питання (-и) оригіналу публікації. Звичайно, це дає підставу зберігати 1 клас у файлі (хоча Лука і Дікам дають хороші моменти), але він не відображає загального консенсусу та не передбачає випадків, коли цього слід уникати.
Роберт Девіс

4
Найкращі практики не існують, якщо ви вірите в найкращі практики, вони розуміють, що вони застосовуються лише до заданого контексту. Як зазначають інші відповіді, бувають випадки, коли це правило фактично створить менш доступний код. Оскільки інструменти покращуються, це правило стає менш актуальним, оскільки набагато простіше знаходити класи та типи в проекті.
abombss

263

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

  1. Полегшує засвоєння та підтримку коду
  2. Робить рішення менш дратівливим (прокручування незліченних непотрібних файлів) і менш повільним
  3. Команда розробників гаразд з цим як з місцевою практикою кодування

Дійсно хороший приклад того, чому я можу отримати кілька класів у файлі:

Скажімо, у мене є кілька десятків спеціальних класів виключень, кожен - 4-х вкладишів, я можу мати окремий файл для кожного або я можу групувати винятки та мати файл на групу. Для мене найбільш раціональним / прагматичним підходом є групування їх, а також лише декілька файлів, тому що це більш ефективна мудра час / кодування (мені не потрібно клацати правою кнопкою миші -> Додати клас, перейменувати, 50 разів) , він зберігає розчин менш захаращеним і краще працює.


92
+1 000. Розуміти обґрунтування найкращих практик та думати двічі, перш ніж їх порушувати - це чудово. Слов'янська прихильність - це зло.
dimimcha

19
Кілька десятків спеціальних класів виключень ? Хіба це не справжнє джерело проблеми? Я не маю на увазі бути тут вибагливим: я думаю, що більшість часу люди хочуть поєднувати заняття в один файл, це тому, що вони без потреби створюють занадто багато типів. (Сказавши це, можливо, є фактичний випадок, коли кілька десятків спеціальних класів виключень мають сенс). Численні невеликі заняття, які не мають права, зазвичай є ознакою більшої проблеми.
Jeff Sternal

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

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

3
Зберігання одного класу на файл та синхронізація імені файлу та імені класу є умовою, як і називання змінних. Visual Studio дуже добре налаштована на такий підхід. Це легше для систем управління джерелами та розробників, які додаються в середині проекту. Вони інтуїтивно шукатимуть ім’я файлу, яке відповідає імені класу.
Oybek

75
static bool GeneralRuleShouldBeFollowed(IGeneralRule rule, IUseCase useCase)
{
    return (rule.Overhead(useCase) 
            < My.PersonalThresholds.ConformismVsPracticality);
}

4
Чи є таке правило в .NET? Я також тільки що повернув результат заяви. : O
Джоан Венге

50

Я іноді групую кілька файлів у файлі, якщо вони щільно з'єднані, і принаймні один з них дуже малий.

Загальна «найкраща практика» - мати один файл на клас.


7
Якщо ви визнаєте, що вони з'єднані, чому ви не роз'єднаєте їх?
Метт

39
@ Метт: Це називається уникати переобладнання. Якщо у вас є кілька щільно з'єднаних класів, і їх роз'єднання додало б великої складності в порівнянні з кількістю практичної гнучкості, яку він надає, то який сенс?
dimimcha

9
Іноді мені подобаються в основному класи "даних", які використовуються лише цим одним класом, тому я зазвичай кладу клас даних у той самий файл, що і користувач, оскільки у datac-lass зазвичай мало логіки, і це здається, що відходи, щоб створити для нього новий файл.
Граф

3
@ Метт: Іноді існують допоміжні класи, які я б стверджував, що вони є прийнятними для зв'язку. Вони зменшують складність для частини іншого класу, але все ж сприяють дуже конкретній цілі цього класу.
Джордан Пармер

6
@TheMatt: Розв’яжіть це: msdn.microsoft.com/en-us/library/… Зв'язок між модулями поганий, але співпраця між класами в межах логічної функції неминуча.
Ben Voigt

25

Крім гіпотетичних аргументів і зосередження натомість на Windows .NET з IDE Visual Studio та зростаючими програмними проектами, в цьому контексті просто має сенс мати один клас на файл.


Взагалі, для візуальної довідки нічого не обійде один клас на файл. Дійсно.

Я не знаю, чи робить це Microsoft чи ні, але вони створили partialключове слово, щоб розділити один клас на кілька файлів (це ще суворіше). Він часто використовується для розділення автоматично створеного дизайнерського коду від вашого власного коду в одному класі (але іноді використовується для того, щоб різні розробники могли працювати над класом одночасно за допомогою різних файлів). Таким чином, Microsoft бачить переваги декількох файлів, і кожен має на увазі безліч думок щодо організації файлів .NET.

Для вкладених класів у вас немає іншого вибору, як використовувати один файл або хоча б перші частини класів у них. У цьому випадку необхідний і точний один файл:

class BicycleWheel {
    class WheelSpoke {
    }
}

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

Крім того, якщо ви використовуєте папки для просторів імен, тоді у вас ніколи не буде зіткнення імені файлу класу. Також зручно знаходити клас за назвою файлу у файловій системі, якщо він не знаходиться в середовищі розробки, наприклад Visual Studio (наприклад, якщо ви хочете швидко редагувати клас за допомогою блокнота або чогось швидкого / легкого ).

Стільки вагомих причин ...


Спасибі, що ви маєте на увазі під "принаймні першими їх частинами"? Ви маєте на увазі, що ви також можете розділити вкладені класи?
Джоан Венге

1
Це непряме посилання на partialключове ключове слово.
Джон К

1
Для запису вкладених класів можна partial msdn.microsoft.com/en-us/library/wa80x488(VS.80).aspx. Я подивився на це з цікавості.
Джон К

Це означає лише, що подання за замовчуванням має бути логічним (область імен / клас), а не фізичним (файли).
Девід Шмітт

@DavidSchmitt - це те, для чого призначено перегляд класів у Visual Studio.
Зак

14

У переважній більшості випадків я дотримуюся правила одного класу на файл. Єдиним винятком, який я регулярно роблю, є визначення перерахунку, яке тісно пов'язане з певним класом. У цьому випадку я часто включатиму визначення визначення enum у файл цього класу.


12

Я теж вважаю, що в один файл повинен бути один тип.

Є одне виняток із цього правила, яке потрібно згадати: наявність двох класів, які відрізняються лише загальним аргументом, таким як:

RelayCommand     

і

RelayCommand<T>

Чи знаєте ви вирішити питання, як зробити StyleCop щасливим у цій справі?
Георгій Полевой

Не погоджуючись, існує ще одна умова для загальних класів, Foo1.cs for Foo <T> `і Foo 2.cs for Foo <T, T1>`.
Ойбек

@Oybek: Що робити, якщо у мене Foo <T>, Foo <U> і Foo <U, T>? А тепер що?
Андрій Ронеа

@AndreiRinea Неможливо мати Foo<T>і Foo<U>в межах одного простору імен. Але якщо простори імен відрізняються, вони зазвичай знаходяться в різних папках. Таким чином для Foo<T>іFoo<U> це має бути Foo 1.cs and for Foo <U, T> `Foo`2.cs. Але все одно один клас на файл.
Oybek

Дякую за інформацію! :)
Андрій Ронеа

8

Дійсно, це зводиться до особистих уподобань. Усі скажуть "один клас на файл", але всі ми маємо свої причини уникати цього за певних обставин. У мене був великий проект, який мав близько 300 різних переліків. Ні в якому разі у мене не буде 300 окремих файлів, по одному для кожного класу, коли деякі перерахунки були лише тридержавними.

Також для людей, які не можуть знайти певні класи, якщо вони не всі у файлах, названих за тим, що вони є, є причина, яку ви не використовуєте Find шукати у всьому рішенні? Використання Find заощаджує мені цінний час, прокручуючи Провідник рішень.


Re: знайти - коли я шукаю визначення типу, я не хочу бачити, де воно використовується. Крім того, пошук займає значно більше часу, ніж прокрутка алфавітно відсортованого списку файлів, які я, мабуть, уже розділив (за простором імен).
Джефф Стернал

1
Зауважую, ви вказали, що працюєте з тим, що розділили по простору імен. Нам, не всім пощастило завжди працювати з проектами, якими ми змогли керувати, на жаль.
Джейсон М

6

Незалежно від того, наскільки легкий вміст, я вважаю, що один клас / інтерфейс / і т.д. на файл є важливим.

Якщо я працюю над великим рішенням у Visual Studio, я хочу мати можливість бачити файли, і не потрібно заглиблюватися всередину, щоб побачити. Навіть з навігаційними інструментами, такими як ReSharper, я хочу 1: 1 відображення.

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


5

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


5

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

Тож справа в тому: розсуд слід використовувати !!!


1
Справжня мудрість, жодне правило в програмуванні не є важким і швидким.
ChaosPandion

4

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


Я вважаю цей аргумент менш цінним для таких інструментів, як ReSharper. Я роблю CTRL + T і починаю вводити назву потрібного типу.
Марк

3
Так, але ви хочете, щоб ваша програма застосувань залежала від стороннього інструменту?
магнус

1
@magnus Я не говорив, що це не причина цього не робити, але менш вагомий аргумент для того, щоб хтось це зробив.
Марк

4

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

У випадках двох або більше класів, коли другий і наступні класи коли-небудь використовуються першим, вони могли б і повинні бути внутрішніми класами, видимими лише для споживчого класу.


3
Коли ви говорите "не більше одного класу вищого рівня в одному просторі імен", ви маєте на увазі в одному namespaceблоці, правда?
Даніель Приден

1
На правила, на які посилається, є SA1403: документ AC # може містити лише один простір імен. SA1402: Документ AC # може містити лише один клас на рівні кореня, якщо всі класи часткові та не мають одного типу.
Стів Гілхам

4

Десь один клас на файл, але ...

Коли декілька класів суворо пов'язані, більше одного класу в одному і тому ж вихідному файлі є IMHO, БОЛЬШЕ, ніж присвячення файлу короткого джерела кожному класу. Джерело є більш читабельним і компактним (і за допомогою #region одне і те ж джерело може бути більш структурованим, ніж раніше).

Враховуйте також, що іноді НЕОБХІДНО розповсюджувати один і той же клас по різним файлам (використовуючи частковий ), оскільки наявність вихідного файлу з 20000+ рядків не є зручним навіть для наявної в мене оперативної пам’яті (але це інше питання).


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

Якщо ви спробуєте генерувати вихідний код (мій випадок - це створення C # прив'язки для OpenGL з його специфікації, маючи тисячі точок введення), важко придумати невеликий клас для великої кількості даних ...
Лука,

3

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

З цим є одна проблема. Врешті-решт малий клас виростає до того моменту, коли він повинен бути у власному файлі, якщо ви перемістите його до нового файлу, ви втратите легкий доступ до вашої історії редагувань.

тобто.

  • у понеділок я вношу зміни до своїх класів x та y у файлі y.css
  • у вівторок я відокремлюю клас x у свій власний файл x.css, оскільки він виріс до великого
  • у середу мій бос хоче побачити, що я змінив у класі x у понеділок, щоб він переглянув історію для x.css, лише x.css не показує історію до зміни вівторка.

1
Що робити, якщо "малий клас" - це щось на зразок похідної EventArgs, який призначений для передачі інформації одержувачам подій вашого класу? Чи зробить код чистішим чи легшим у підтримці, перемістивши таку річ в інший файл? Можливо, така річ має бути вкладеним громадським класом, але вони, здається, також нахмурилися. Що стосується історії ревізій, чи не з’явився б клас нізвідки в журналі змін, і чи не слід було б коментувати примітку коду, звідки він узятий?
supercat

Я б класифікував це як very tightly relatedклас і залишав би його за умови, що він займає лише невелику кількість екранного простору і не використовується для тих же цілей жодним іншим класом.
пряник

3

Це справді проблема? :)
Дійсно невеликі класи, як і переліки, можна скласти разом з іншими. Дотримуватись одного правила: складайте лише класи, які мають щось спільне.

Як відступ - в одному з моїх проектів я маю файл із 150 класами всередині. У файлі 10000 рядків коду. Але це автоматично генерується, так що це цілком прийнятно :)


1
У мене той самий файл із 120 класами та 750 підкласами з півмільйона мільйонів рядків, він також автогенерований. Проблема полягає в тому, що: якщо я натискаю на нього, я повинен перезавантажитися, тому що все зупиняється.
Behrooz

3

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


1
Що ви маєте на увазі під «котловою декларацією про імпорт»? "Використання висловлювань"? Але чи не будуть заняття в одному просторі імен?
Джоан Венге

3
@Joan: Я маю на увазі необхідність імпортувати 15 різних, але пов'язаних з ними модулів, щоб зробити щось дійсно просте. Можливо, це не стосується спеціально C #. Я насправді не знаю C #, але в інших мовах це досить дратівлива проблема.
дзимча

Дякую, що тому я розгубився.
Джоан Венге

2

Я це роблю, але лише тоді, коли заняття пов’язані між собою з дітьми-батьками, а дочірні класи використовуються ТОЛЬКО батьком.


Дякую, але чому ви не розділите його в інший файл? Просто цікаво.
Джоан Венге

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

2

Я зазвичай дотримуюся одного класу на файл. Але я зроблю винятки для груп подібних конструкцій, які використовуються в рамках проекту. Наприклад:

  • EventArgs.cs, який містить будь-які EventArgsпідкласи, оскільки вони, як правило, лише 5-10 рядків коду, але зазвичай вони використовуються декількома різними класами. Крім того, я можу помістити EventArgsкласи в той самий файл, що і клас, який оголошує події.
  • Delegates.cs, який містить Делегатів, які використовуються протягом усього проекту, оскільки вони зазвичай мають лише 1 рядок. Знову ж таки, альтернатива полягає в тому, щоб помістити їх у один і той же файл з класом, який викриває / споживає їх.
  • Enums.cs, який містить enums, використовуваний протягом усього проекту. (Якщо є такий, enumякий використовується лише одним класом, я зазвичай перейду privateдо цього класу.)

2

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


2

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


2

Поки що відповіді, як видається, обертаються навколо винятків людей із цього правила, тому ось моє: я зберігаю класи та їхні метадані «приятельські» класи разом, коли використовую пакет DataAnnotations в .NET3.5 SP1. В іншому випадку вони завжди знаходяться в окремих файлах. Знаєте, більшість часу. За винятком випадків, коли їх немає.


2

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

Або окремий клас, який містить деякі методи розширення для цього основного класу.


1

One case could be:коли ваші класи спільно утворюють а, module / unitякий обслуговує деякі основні класи, наприклад helper classes, інші мудрі ні .

подивіться вихідний код проекту ASP.NET MVC 2.0 . Це суворо дотримується цього правила


1

Мені подобається ідея створити менші класи та переконатися, що клас робить лише те, що він повинен робити. Якщо у вас є кілька класів, які сприяють вирішенню однієї проблеми, немає шкоди для об'єднання їх в один файл.

Я б не дотримувався практики MS, оскільки вони не найкращі ПРАКТИКИ!


1

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

Наприклад: у вас можуть бути два класи, коли один клас використовує Linq, а другий - ні.

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


0

Ще одна причина для одного класу на файл, що не згадується у відповідях, розміщених дотепер, полягає в тому, що один клас на файл полегшує розуміння впливу PR під час огляду коду. Це також зменшує конфлікти злиття.

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

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

З цього правила є винятки (інтерфейс + реалізація, перерахунки, ...), але це краще місце, ніж навпаки, яке, як правило, дозволяє молодшим розробникам поєднувати всі типи непов'язаних класів у один і той же файл.

Один клас на файл - це явне однозначне правило, яке не підлягає тлумаченню.


Файл з пов'язаними класами в архіві підпорядковується особистим уподобанням та інтерпретації (як видно з усіх інших відповідей тут щодо того, коли це нормально використовувати), і тому це погане правило.


-1

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

Мені цікаво, чи будь-які ваші відповіді змінюються залежно від того: ви: (1) розробляєте додаток Windows Forms, веб-додаток, бібліотеку чи інше; або (2) використовуючи Visual Studio чи ні. При використанні VS може виявитися, що правило одного класу на файл також передбачає один клас на проект VS, оскільки, схоже, є консенсус в інших потоках, рішення / проекти VS повинні відображатися в імені та структурі файлів / файлів. Справді, моє враження таке, що concensus повинен мати ім'я проекту = назва збірки = (вкладене) ім’я простору імен, яке все потім відображатиметься в імені та структурі файлів / імен. Якщо це правильні вказівки (або правила), то всі ці, здавалося б, ортогональні механізми організації все-таки будуть синхронізовані.


-1

Так, для читабельності у нас повинен бути один файл на клас! Просто вскочив у проект. Я бачу багато класів в одному файлі. новому хлопцеві це просто так важко зрозуміти. не варто думати про ремонтопридатність? коли ми розробляємо програмне забезпечення? багато разів розвиток буде продовжено іншими розробниками. У нас є простори імен, щоб упорядкувати наші речі, для цього нам не потрібні файли !.


-5

Один елемент коду на файл, так.

Все інше - це неправильне дію - і, чесно кажучи, ознака жертви RAD.

Як тільки хтось почне належну розробку програмного забезпечення (IoC, шаблони дизайну, DDD, TDD тощо) і залишить "omg дозволяє це зробити, я не маю уявлення, як, але мені платять" майданчик, ви побачите, що це правило справді, дійсно, має значення.

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