Чи повинні методи C #, які * можуть бути статичними, статичними? [зачинено]


103

Методи # Повинен чи C , які можуть бути статичними бути статичним?

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

Питання: чи має бути статичним? Це не статично за конструкцією чи вибором, просто за своєю природою, оскільки не посилається на будь-які екземпляри.


1
Досить точний дублікат stackoverflow.com/questions/169378 / ...
JasonTrue

41
"Досить точним" є оксиморон
Метт Бріггс

1
Resharper , інструмент інструментів Visual Studio, говорить так! :-)
Ребекка

@Junto Можливо, у вашій версії, але мій говорить, що можна зробити статичним ...
Роббі Ді

Відповіді:


59

Це залежить. Є дійсно 2 типи статичних методів:

  1. Методи, які є статичними, оскільки вони МОЖУТЬ бути
  2. Методи, які є статичними, оскільки вони МАЮТЬ бути

У кодовій базі невеликого та середнього розміру ви дійсно можете поводитися два способи взаємозамінно.

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

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

Це може призвести до будь-якого:

  1. Дублювання коду
  2. Вибух у кількості аргументів методу

Обидва ці речі погані.

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

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

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

Отже, для великих проектів не можна робити речі статичними, якщо вони вам не потрібні. Для невеликих проектів просто робіть те, що вам найбільше подобається.


43

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

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

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


6
Домовились. Я зазвичай роблю метод "приватним статичним" у такому випадку.
harpo

6
Я також не вважав би приватну статичну. Головне - запитати себе: чи логічно підходить цей метод як частина цього типу, чи це просто тут, для зручності? Якщо остання, чи може вона краще підходити десь ще?
Joel Coehoorn

1
На кшталт: "чи міг новий метод логічно належати в іншому місці" - підказка, чи він не покладається на місцевий стан, можливо, тип повернення - там, де він належить?
AndyM

20

Не обов'язково.

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


Я думаю, що він здебільшого має на увазі приватні методи
Джордж Мауер

@Ray - Правильно, це стосується лише приватних членів. Я оновив свою відповідь, щоб це відобразити.
Майкл

Мої думки точно - тільки тому, що ви могли зробити щось статичне, не означає, що потрібно чи потрібно .....
marc_s

То що б ви зробили для приватних методів, які можна зробити статичними?
Рей

@Ray - Мабуть, залиш, як є, поки у мене не буде достатньо вагомих причин перейти до статики.
Майкл

13

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


11

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


7
Не обов'язково. Статичний метод не матиме доступу до інформації про екземпляри, немає членів, як ви сказали, але він може взаємодіяти з іншими класами, а також з іншим поширеним методом. Бути статичним не означає, що зв'язок знижується обов'язково. Однак я зрозумів вашу думку.
Віктор Родрігес

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

8

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


6

Особисто я великий фанат бездержавності. Чи потрібен ваш метод доступу до стану класу? Якщо відповідь «ні» (а це, мабуть, «ні», інакше ви б не вважали, що це стати статичним методом), то так, продовжуйте це.

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

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

Так що так, будьте всі, будь ласка.


1
Статичний метод все ще може мати доступ до стану. Він просто отримує стан від переданого йому об'єкта. І навпаки, поля екземплярів не обов'язково містять стан, що змінюється.
Jørgen Fogh

6

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


3
Це технічно вірно, але не в реальному матеріальному сенсі. Різниця між статичним / не дуже, дуже рідко буде фактором продуктивності.
Foredecker

22
-1: Передчасна оптимізація підручника. Швидкість, звичайно, не повинна бути першим критерієм при вирішенні статичного порівняно з нестатичним для загального випадку.
Не впевнений,

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

5
Моя думка, швидкість - одна з найбідніших причин, яку ви можете мати для вирішення того, чи є функція статичною проти нестатичною у 99% випадків. Є набагато важливіші міркування щодо дизайну ОО, які розробляються в інших посадах.
Не впевнений,

2
@agnieszka: Особливою причиною загального використання методів екземплярів замість статичних методів є стан. Якщо ви залишите собі методи статичними, у складному додатку ви введете помилок, які змусять вас вирвати волосся. Подумайте над зміною глобального стану, умов перегонів, безпеки ниток тощо.
Шандор Давідхазі,

5

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

Коли ви пишете код, ви повинні писати його так, щоб ви виставляли якомога менше, а також, щоб у вас був доступ якнайменше.

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

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


4

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

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

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


4

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


2

Особисто мені не було б нічого іншого, як зробити це статичним. У цьому випадку Resharper видає попередження, і наш прем'єр-міністр має правило "Немає попереджень від Resharper".


1
Ви можете змінити налаштування ReSharper: P
Бернхард Хофманн

1
Якби це було так просто, у нас не було жодних побоювань від Resharper ... колись :)
Prankster

1

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


Так, але якщо колись вам потрібно це зробити, ви завжди можете зробити це не статичним. Або я щось пропускаю?
Рей

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

Усі сайти викликів повинні бути змінені зі статичного виклику методу на виклик функції члена.
Брайан Енсінк

Вибачте, ви додали це після мого коментаря. На моїй думці я думав про приватні методи, але це справедливий момент для публічних методів.
Рей

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

1

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


1

Подумайте про свої методи та заняття:

  • Як ти збираєшся їх використовувати?
  • Вам потрібно багато доступу до них з різних рівнів вашого коду?
  • Це метод / клас, який я можу використовувати майже в кожному розробленому проекті.

Якщо останні два "так", то ваш метод / клас, ймовірно, повинен бути статичним.

Найбільш використовуваний приклад, мабуть, Mathклас. Кожна основна мова ОО має її, і всі методи є статичними. Тому що вам потрібно мати можливість їх використовувати де завгодно, у будь-який час, не роблячи примірників.

Ще один хороший приклад - Reverse()метод у C #.
Це статичний метод у Arrayкласі. Він змінює порядок масиву.

Код:

public static void Reverse(Array array)

Він навіть нічого не повертає, ваш масив обернено, тому що всі масиви - це екземпляри класу Array.


Математика - поганий приклад. Я думаю, що це краще: newnumber = number.round (2), ніж newnumber = Math.round (число)
графічно

3
Клас Math - ідеальний приклад використання статичних класів. Ось про що йдеться в цій темі, а не про те, як ви віддаєте перевагу округленню чисел ...
KdgDev

1

Поки ви робите новий метод приватним статичним, це не є переломною зміною. Фактично, FxCop включає це керівництво як одне із своїх правил ( http://msdn.microsoft.com/en-us/library/ms245046(VS.80).aspx ) із такою інформацією:

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

Враховуючи це, перший коментар Девіда Кіна більш коротко підсумовує занепокоєння, кажучи, що це насправді швидше правильність, а не підвищення продуктивності:

Хоча це правило класифікується як питання про ефективність, поліпшення продуктивності статичного методу становить лише близько 1%. Швидше, це скоріше питання коректності, який може вказувати на неповний або помилку в члені через його невживання інших членів екземпляра. Позначення методу статичним ( Спільним у Visual Basic) дає зрозуміти про намір не торкатися стану екземпляра.


1

Я б неодмінно перетворив усе, що можу, на статичне з іншої причини:

Статичні функції, коли JIT'd, викликаються без параметра "цей". Це означає, наприклад, що 3-х параметрична нестатична функція (метод-член) висувається з 4 парам на стеку.

Та ж функція, складена як статична функція, буде викликана з 3 параметрами. Це може звільнити регістри для JIT та заощадити простір стека ...


1

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

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


1

По суті статичні методи, які чомусь робляться нестатичними, просто дратують. А саме:

Я дзвоню в свій банк і прошу баланс.
Вони просять номер мого рахунку.
Досить справедливо. Метод екземпляра.

Я дзвоню в свій банк і запитую їх поштову адресу.
Вони просять номер мого рахунку.
WTF? Fail - повинен був статичним методом.


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

0

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


-1

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

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