Метод можна зробити статичним, але чи слід?


366

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


20
Чи насправді Решарпер не кричить "низька згуртованість, низька згуртованість"? настав час подивитися, чи дійсно метод належить до цього класу.
ПК

Відповіді:


245

Статичні методи проти методів екземплярів
10.2.5 Статичні та екземплярні члени специфікації мови C # пояснюють різницю. Як правило, статичні методи можуть забезпечити дуже невелике підвищення продуктивності порівняно з примірниками методів, але лише в дещо екстремальних ситуаціях (див. Цю відповідь для отримання додаткових деталей про це).

Правило CA1822 у аналізі FxCop або коду визначає:

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

Клас утиліти
Ви не повинні переміщувати їх у клас корисності, якщо це не має сенсу у вашому дизайні. Якщо статичний метод відноситься до певного типу, подібно до ToRadians(double degrees)методу, що відноситься до класу, що представляє кути, має сенс існувати як метод статичного члена цього типу (зверніть увагу, це зведений приклад для демонстрації).


2
> компілятор видаватиме цим членам невіртуальні сайти викликів. Фактично це "компілятор може випромінювати ...". Я пам’ятаю щось про компілятор C #, що використовує callvirt замість виклику, щоб обійти якусь потенційну помилку.
Джонатан Аллен

24
Я вирізаю і вставляю його безпосередньо з FxCop 1.36. Якщо FxCop помиляється, досить справедливо.
Джефф Йейтс

5
@Maxim Не впевнений, що я ціную вислів "фігня"; досить грубий спосіб підійти до незнайомців. Однак основна точка є дійсною; Я трохи оновив речі (це було 9 років тому, тому я не пригадую основи моєї первісної претензії).
Джефф Йейтс

10
@Maxim Ваш пункт недійсний. Запевняю вас, що я не мав хорошого рейтингу 9 років тому. Я вдячний зауваженнями, які вказують на помилки (або редакції, що їх виправляють), але не будьте грубими та не покладайте необґрунтованих очікувань на інших. Не називайте щось "фігня"; це передбачає наміри обдурити, а не чесно ставитись до помилки добра чи незнання. Це грубо. Я волонтеризую свій час, щоб допомогти тут, і це дійсно безглуздо, коли до нього ставляться з неповагою. Не кажіть мені, на що мене ображати - це мій вибір, а не ваш. Дізнайтеся, як зробити свою точку з повагою та цілісністю. Дякую.
Джефф Ейтс

2
@Maxim Хоча делегати не зберігаються поряд з кожним екземпляром, кожен екземпляр класу без громадянства дійсно займає деяку пам’ять на купі, що марно накладні. Зазвичай сервіси екземплярів - це не гарячий шлях у додатку, але якщо ваша програма закінчить побудувати багато цих об'єктів, вона збирається створити тиск GC, якого можна уникнути, просто використовуючи статичні методи. Оригінальна заява ОП про те, що в екстремальних ситуаціях статичні методи забезпечують корисні показники для випадків без громадянства, була належним чином відхилена та обгрунтована.
Асад Саедюддін

259

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

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


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

2
"Іноді існують методи, які логічно діють на екземпляр, але поки не буває, що вони використовують жоден стан держави. Наприклад," Мені сподобалося, що ви використовували "для прикладу" в цьому випадку.
PaulBinder

56

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

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


22

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

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

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

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


4
Ваша проблема полягає в статичних полях / властивостях, а не статичних методах.
Асад Саедюддін

10

Це цікаво читати:

http://thecuttingledge.com/?p=57

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

але ось що пише документація про переробку: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
Я думаю, що цей пункт недооцінений. Що інструмент насправді говорить вам, це те, що метод працює лише на інших членах класу. Якщо це якийсь об’єкт командування (або "використання випадку" або "інтерактор"), відповідальність за те, щоб маніпулювати іншими об'єктами, це добре. Однак, якщо він маніпулює лише одним класом, який дуже схоже на Feature Envy .
Грег

9

Просто , щоб додати до @Jason True в відповідь , це важливо розуміти , що просто покласти «статичний» на метод не гарантує , що метод буде «чистим». Це буде без громадянства щодо класу, в якому він оголошений, але він може отримати доступ до інших "статичних" об'єктів, які мають стан (конфігурація програми тощо), це не завжди може бути поганою справою, але одна з причин того, що Особисто я віддаю перевагу статичним методам, коли можу, це те, що якщо вони чисті, ви можете перевірити їх і міркувати поодиноко, не турбуючись про навколишній стан.


6

Вам слід зробити те, що є найбільш читаним та інтуїтивно зрозумілим у визначеному сценарії.

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


6

Для складної логіки в класі я знайшов приватні статичні методи, корисні при створенні ізольованої логіки, в якій вхідні екземпляри чітко визначені в підписі методу і жодних побічних ефектів примірника не може виникнути. Всі виходи повинні бути через параметри повернення або вихід / ref. Розбиття складної логіки на кодові блоки без побічних ефектів може покращити читабельність коду та впевненість у ньому команди розробників.

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


5

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


3

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


3

Зробити метод статичним означає, що ви можете викликати метод поза класом, не створюючи попередньо екземпляр цього класу. Це корисно при роботі з сторонніми об’єктами постачальників або надбудовами. Уявіть, якби вам довелося спочатку створити об’єкт консолі "con" перед тим, як викликати con.Writeline ();


Java запропонувала б вам створити заводський екземпляр для створення об'єкта Console перед викликом con.Writeline ().
ScottMichaud

2

Це допомагає контролювати забруднення простору імен.


8
Як створення статичного методу допомагає уникнути забруднення простору імен?
замок

1
З досвіду, групуючи методи в класи зі статичними методами, ви уникаєте досвіду необхідності префіксувати всі «захоплення мішка» вільних функцій, які можуть суперечити іншим бібліотекам або вбудованим функціям. За допомогою статичних методів вони ефективно розміщуються під іменем Classname, наприклад. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi

0

Просто моя tuppence: Додавання всіх загальних статичних методів до класу утиліти дозволяє додавати

using static className; 

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

Я поняття не маю, хороша практика це чи ні. У мене так багато, щоб дізнатися про C # 4/5 і стільки застарілого коду для рефактора, що я просто намагаюся дозволити, щоб підказки Роузліна мене керували.

Джої


0

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

Моя коротка відповідь: Так, ви можете конвертувати їх у статичні методи, якщо пропонує Решарпер. Шкоди в цьому немає. Швидше, роблячи метод статичним, ви фактично оберігаєте метод, щоб, без необхідності, не підсунути жодних членів екземпляра до цього методу. Таким чином, ви можете досягти принципу ООП " Мінімізуйте доступність класів та членів ".

Коли ReSharper припускає, що метод екземпляра може бути перетворений в статичний метод, він насправді говорить вам: "Чому .. цей метод сидить у цьому класі, оскільки він фактично не використовує жодного з його станів?" Отже, це дає вам їжу для роздумів. Тоді саме ви можете усвідомити необхідність переходу цього методу до статичного класу корисності чи ні. Відповідно до принципів SOLID, клас повинен нести лише одну основну відповідальність. Таким чином, ви можете зробити краще очищення своїх класів таким чином. Іноді вам потрібні деякі допоміжні методи навіть у вашому класі екземпляра. Якщо це так, ви можете тримати їх у помічнику #region.

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