Навіщо використовувати часткові класи?


72

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

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


10
Це насправді не "ціле ключове слово". Це контекстне ключове слово . partialщось означає лише тоді, коли йдеться раніше class. Ви можете використовувати його як ім'я ідентифікатора в інших частинах коду тощо.
Дін Хардінг,

4
Якщо ви їх використовуєте, і це не для генерованого коду, я ненавиджу вас. Не ти особисто, а взагалі ти. Я ненавиджу знімати код через часткові класи.
Стівен Еверс

3
"Вишукувати код" не важко, всі методи класу все ще відображаються у спадному вікні VS, незалежно від того, яку частину часткової частини ви шукаєте. Інші навігації з кодом також спрацьовують (або "розумна" навігація в стилі R # або стара стара зручна зміна-ctrl-f
Стів

2
Нерозуміння, що часткові класи повинні бути в окремих файлах.
Барт

Відповіді:


110

Це дуже корисно в будь-якому сценарії, коли одна частина класу генерується певним спеціальним інструментом, оскільки дозволяє додавати власну логіку до згенерованого коду без успадкування згенерованого класу. Btw. Існують також часткові методи з тієї ж причини.

Це стосується не лише інтерфейсу користувача, але й інших технологій, таких як Linq-To-Sql або Entity Framework.


44
Крім того, це дозволяє тримати код під контролем версій, залишаючи згенерований код поза контролем версій.
Френк Шірар

3
Добрий момент, я ніколи про це не думав. Я бачив, як це зловживають на практиці, хоча. Спосіб (паршивих) програмістів зберегти розмір файлу керованим.
Мартін Вікман

1
Найкращі приклади, які я використав, це: а) контексти даних Linq до SQL, де ви хочете розширити класи; б) продовжити заняття, передані з веб-служб. У жодному разі це не є зловживанням, а також не є засобом збереження розмірів файлів керованими ... Я був би радикально незадоволений, побачивши, що він використовується таким чином (і вжив би заходів ...)
Мерф

3
Класи WinForm використовують його для приховування всіх елементів дизайнерського коду, створюючи елементи керування (особливо важливо, оскільки дизайнер любить випадковим чином упорядкувати весь створений ним код, що призводить до величезних помилок при різниці / звинуваченні), і якщо ви працюєте з XML, інструмент XSD може знову створити часткові класи із файлу схеми, що дозволяє вам відокремити код від автоматично створеного сортування.
Dan Neely

2
@MartinWickman не обов'язково хитрий. Це хороша відправна точка для рефакторингу Божих об’єктів у застарілому коді. Спробуйте очистити пейзаж, розділивши спочатку великі класи на окремі файли. (Я знаю, що ваш коментар дуже давній)
Конрад Моравський

26

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

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

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


9
Я ніколи не думав використовувати часткові класи для розділення реалізацій інтерфейсу, це відмінна ідея.
Марк Бут

Йдеться про набагато більше, ніж про стиль. Розробникам генератора коду доведеться стрибати через обручі, щоб дозволити вам редагувати код у файлі, яким керує генератор, і навіть тоді це буде проблематично. Перевага №1, для мене, дає вам місце для написання коду, до якого генератор не може / чіпати. Це досить відчутна користь.
Даніель

19

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

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


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

2
Так, це не виправдання того, що це є мовою, але це цікавий спосіб їх використання.

18

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

  • Щоб відокремити створений інструментом / IDE / дизайнером код від коду, який ви підтримуєте. Хороший приклад - Form.Designer.csфайл, який містить код, створений дизайнером для програм Windows. У багатьох інших форматах .NET також є якийсь код, створений інструментом, який може бути потенційно відроджений під час створення проекту, і, таким чином, всі ваші користувацькі зміни будуть видалені. Розділення допоможе вам захистити свій код і зміни від таких автоматизованих модифікацій.

  • Коли ви реалізуєте декілька інтерфейсів з великою кількістю коду в реалізації. Я , як правило , використовувати окремий частковий файл для кожного такого інтерфейсу, називаючи це наступним чином : {Class}.{Interface}.cs. Мені легко бачити в IDE, які інтерфейси {Class}реалізовані та як.

  • Коли клас повинен містити один або кілька вкладених класів , особливо з достатньою кількістю коду в них, щоб бути поміщеним в окремий файл. Я б дотримувався вищезазначеної схеми і використовував {Class}.{NestedClass}.csумову іменування для кожного вкладеного класу. Аналогічна практика вже згадується у відповіді Віртлінка .

  • Коли я пишу staticкласи, які будуть використовувати методи розширення . Часто трапляється надавати однакову логіку методу розширення для подібних класів або інтерфейсів - як, наприклад, Reverseу загальних і негенеричних колекціях. Я б поклав усі методи розширення для одного класу чи інтерфейсу в окрему частку статичного класу. Наприклад, я мав би всі методи розширення IListінтерфейсу в одному місці і ті ж методи, що і IList<T>в іншому файлі. Іншим підходом було б покласти той самий метод (усі його перевантаження) в той самий частковий, з усіма можливими класами для thisпараметра - як, щоб мати всіReverseреалізації в одному файлі. Залежить від того, який з них краще виправдати розділення з точки зору обсягу коду, або деяких внутрішніх конвенцій, які ви або ваша організація можуть дотримуватися

  • Я цим не користуюся, але я бачив, як деяким C / C ++ людям подобається підхід, який я опишу тут: створити частку для класу лише частковими методами . Це нагадує спосіб C / C ++ для визначення інтерфейсів та відокремлення декларації методу від реалізації.

  • Розмежування з чисто логічних питань . Якщо вам трапляється працювати з великим класом, який поєднує в собі більше одного логічного набору операцій, то ви можете розділити кожен пов'язаний з логікою код на окрему частку. Зазвичай існування таких класів суперечить принципу розділення проблем , але це часто спостерігається у реальному випадку, особливо для старих кодових баз. Користувач Стів Еверс згадав їх у своїй відповіді на це питання , посилаючись на них за назвою об'єктів бог. Я особисто використовував підхід часткових класів, щоб розділити код до того, як відбудеться рефакторинг таких дійсно великих файлів, щоб полегшити роботу та зробити рефакторинг більш прозорим. Це також зменшить конфлікти, які я потенційно можу викликати, коли задіяні такі версійні версії як SVN.


14

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

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

Це також означає , що клас NestedClassвкладений MyClassматиме свій власний файл в моїх проектах: MyClass.NestedClass.cs.

partial class MyClass
{
    private class NestedClass
    {
        // ...
    }
}

1
Цікаво, чому можна було б проголосувати цю відповідь. Згадана практика не є ні анти-закономірністю, ні вона не спричинить жодних мені відомих проблем.
Івайло Славов

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

10

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

Тож, коли ви запитуєте, Why use partial classes?я відповідаю: якщо ви не використовуєте згенерований код, не робіть цього.


+1. Вперше я бачу такі типи об'єктів, що називаються іменем (богові об'єкти), і це навіть офіційно. Ніколи не пізно дізнатися щось нове.
Івайло Славов

6

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

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

1

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


1

Я можу подумати про брудне використання для них.

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

В основному ви хочете зробити багато спадкових, але C # не подобається. Отже, ви робите часткове використання для створення того, що по суті є #include в C / C ++;

Поставте всю функціональність у клас або використовуйте хелперний клас. Потім скопіюйте помічник X разів і перейменуйте його на частковий клас A, B, C. і покладіть частку на ваші класи A, B, C.

Відмова: Так, це зло. Ніколи цього не робіть - особливо якщо це змусить інших людей злитися на вас.


Міксини. Це може поєднуватися з T4, щоб уникнути копіювання вручну ...
Пітер Тейлор

Як зазначалося, це дуже нагадує міксини. Однак ви підходите до концепції, відомої як "риси", і вони спокійно впораються з тим, чого ви намагаєтеся досягти. У мене є мовно-агностичний опис у publius-ovidius.livejournal.com/314737.html Я шукав чисту реалізацію для C #, але не бачив її.
Овід
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.