Переваги використання приватних статичних методів


209

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

Приклад:

foreach (XmlElement element in xmlDoc.DocumentElement.SelectNodes("sample"))
{
    string first = GetInnerXml(element, ".//first");
    string second = GetInnerXml(element, ".//second");
    string third = GetInnerXml(element, ".//third");
}

...

private static string GetInnerXml(XmlElement element, string nodeName)
{
    return GetInnerXml(element, nodeName, null);
}

private static string GetInnerXml(XmlElement element, string nodeName, string defaultValue)
{
    XmlNode node = element.SelectSingleNode(nodeName);
    return node == null ? defaultValue : node.InnerXml;
}

Чи є якась перевага визначити методи GetInnerXml () статичними? Немає відповідей думки, будь ласка, у мене є думка.


Відповіді:


221

На сторінці правил FxCop на цій сторінці :

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


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

20
Я б сказав, що: "Якщо методу не потрібен доступ до держави (це), зробіть його статичним", як загальне правило.
DanMan

3
В інтересах балансу варто зазначити, що багато людей, як правило, проти статичних методів, оскільки вони порушують поліморфізм, а значить, об'єкт не може бути затримані для тестування. наприклад дивіться googletesting.blogspot.co.uk/2008/12/…
Енді

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

4
Багато розробників не знайомі з "приватною статикою". Я використовував це в загальній кодовій базі моєї команди, і це призвело до плутанини. Натомість це дає дуже незначну вигоду. Ми можемо навчити всіх членів команди, включаючи всіх майбутніх розробників, які підтримують код, щодо того, що це означає. Але вигода від переходу приватного методу на приватну статику настільки незначна (тобто видалення залежності від даних про екземпляр), що не варто докладати зусиль і плутанини. У будь-якому випадку метод вже є приватним. Це мовна вигадка, яку насправді не потрібно знати.
Кертіс Яллоп

93

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

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

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

Візьмемо цей приклад:

Бібліотека громадського класу
{
    приватна статична книга Пошук книги (Список <Книга> книги, назва рядка)
    {
        // код іде тут
    }
}

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

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


1
Вид оголошення методом const в C ++, чи не так?
anhoppe

Так - це ще один хороший спосіб використовувати мову для спрощення речей, обмеживши те, що може піти не так.
Ніл

Це не обов'язково вірно. Давайте припустимо , що Libraryє поле примірника , List<Book> _booksщоб зберегти його в книги (Не так, як ви б створити Libraryклас , можливо , але ж / д), і передає цей список findBook, і що виклики методів статичних books.Clear()або books.Reverse()і так далі. Якщо ви надаєте статичному методу доступ до посилання на якийсь стан, що змінюється, то цей статичний спосіб може дуже зіпсувати ваш стан.
сара

1
Правда. І в цьому випадку підпис показав би нам, що цей метод мав доступ до (і можливість мутувати) екземпляр Бібліотеки.
Ніл

Практично для будь-якої захисної конструкції, яку ми могли б використати, є спосіб її підірвати. Але використання їх все-таки мудре і допомагає підштовхнути нас у правильному напрямку, до «ями успіху».
Ніл

81

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

src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx


15

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


Як це стосується переваги продуктивності чи пам’яті під час виконання?
Скотт Дорман

11
Передача додаткового параметра означає, що ЦП повинен виконати додаткову роботу, щоб помістити цей параметр у регістр, і натиснути його на стек, якщо метод екземпляра викликає інший метод.
Kent Boogaart

5

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

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


4

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


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

3
Ні, але якщо він використовується статичним методом, він ОБОВ'ЯЗКОВО статичний. Якщо метод не був статичним, ви, можливо, не зробили статичного члена статичним, і це призвело б до використання більшої кількості пам'яті для кожного примірника класу.
Joel Coehoorn

2

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

public class MyClass
{
    private readonly MyDependency _dependency;

    public MyClass(MyDependency dependency)
    {
        _dependency = dependency;
    }

    public int CalculateHardStuff()
    {
        var intermediate = StepOne(_dependency);
        return StepTwo(intermediate);
    }

    private static int StepOne(MyDependency dependency)
    {
        return dependency.GetFirst3Primes().Sum();
    }

    private static int StepTwo(int intermediate)
    {
        return (intermediate + 5)/4;
    }
}

public class MyDependency
{
    public IEnumerable<int> GetFirst3Primes()
    {
        yield return 2;
        yield return 3;
        yield return 5;
    }
}

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

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

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


-3

Як уже було зазначено, у статичних методів є багато переваг. Однак; майте на увазі, що вони будуть жити на купі протягом життя програми. Нещодавно я провів день, відслідковуючи витік пам'яті в службі Windows ... витік був викликаний приватними статичними методами всередині класу, який реалізував IDisposable і послідовно викликався з використовуючого оператора. Кожного разу, коли цей клас створювався, пам’ять резервувалась у купі для статичних методів у класі, на жаль, коли клас утилізувався, пам'ять для статичних методів не вивільнялася. Це призвело до того, що слід пам’яті цієї послуги споживає наявну пам’ять сервера протягом декількох днів із прогнозованими результатами.


4
Це не має сенсу. Купа ніколи не зберігає пам'ять для коду для будь-яких методів, статичних чи інших. Купа призначена для екземплярів об'єкта. На стеку будуть дані для будь-якого виклику будь-якого методу (для збереження пам'яті для параметрів, повернення значення, не піднятих локальних пристроїв тощо), але все це відходить, коли метод закінчить виконання.
Серві
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.