Преимущества использования частных статических методов - PullRequest
186 голосов
/ 25 сентября 2008

При создании класса, который имеет внутренние частные методы, обычно для уменьшения дублирования кода, которые не требуют использования каких-либо полей экземпляра, есть ли преимущества в производительности или памяти для объявления метода как статического?

Пример:

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 () как статических? Нет мнений, пожалуйста, у меня есть мнение.

Ответы [ 8 ]

198 голосов
/ 25 сентября 2008

Со страницы FxCop rule об этом:

После того, как вы пометите методы как статические, компилятор отправит не виртуальные сайты вызовов этим участникам. Создание не виртуальных сайтов вызовов предотвратит проверку во время выполнения для каждого вызова, которая гарантирует, что текущий указатель объекта не равен нулю. Это может привести к ощутимому приросту производительности для чувствительного к производительности кода. В некоторых случаях невозможность доступа к текущему экземпляру объекта представляет проблему правильности.

83 голосов
/ 07 ноября 2008

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

  • Методы, которые используют / изменяют текущее состояние экземпляра.
  • Вспомогательные методы, которые не используют / не изменяют текущее состояние объекта, но помогают мне вычислить значения, которые мне нужны в другом месте.

Статические методы полезны, потому что, просто взглянув на его сигнатуру, вы узнаете, что вызывающий его не использует и не изменяет состояние текущего экземпляра.

Возьмите этот пример:

public class Library
{
    private static Book findBook(List<Book> books, string title)
    {
        // code goes here
    }
}

Если экземпляр состояния библиотеки когда-либо облажался, и я пытаюсь выяснить, почему, я могу исключить findBook в качестве виновника, просто по его подписи.

Я стараюсь как можно больше общаться с помощью сигнатуры метода или функции, и это отличный способ сделать это.

73 голосов
/ 04 сентября 2012

При вызове статического метода создается инструкция вызова на промежуточном языке Microsoft (MSIL), тогда как при вызове метода экземпляра создается инструкция callvirt, которая также проверяет наличие ссылок на нулевые объекты. Тем не менее, в большинстве случаев разница в производительности между ними незначительна.

Источник: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx

13 голосов
/ 25 сентября 2008

Да, компилятору не нужно передавать неявный указатель this в static методы. Даже если вы не используете его в своем методе экземпляра, он все еще передается.

5 голосов
/ 25 сентября 2008

Это будет немного быстрее, так как этот параметр не передается (хотя стоимость вызова метода, вероятно, значительно больше, чем экономия).

Я бы сказал, что лучшая причина, которую я могу придумать для частных статических методов, заключается в том, что это означает, что вы не можете случайно изменить объект (так как указатель отсутствует)

4 голосов
/ 25 сентября 2008

Это заставляет вас помнить, что вы также должны объявлять любые члены в области класса, которые функция также использует как статические, что должно сохранить память для создания этих элементов для каждого экземпляра.

2 голосов
/ 27 апреля 2016

Я очень предпочитаю, чтобы все частные методы были статическими, если они действительно не могут быть такими. Я бы предпочел следующее:

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 # позволяют вам извлечь класс из набора приватных статических методов несколькими нажатиями клавиш. Попробуйте сделать это, когда все частные вспомогательные методы тесно связаны с полем экземпляра, и вы увидите, что это может быть довольно головной болью.

0 голосов
/ 12 октября 2016

Как уже было сказано, статические методы имеют много преимуществ. Тем не мение; имейте в виду, что они будут жить в куче на протяжении всей жизни приложения. Недавно я провел день, отслеживая утечку памяти в службе Windows ... утечка была вызвана частными статическими методами внутри класса, который реализовал IDisposable и был последовательно вызван из оператора using. Каждый раз, когда этот класс создавался, в куче зарезервировалась память для статических методов внутри класса, к сожалению, когда класс был удален, память для статических методов не освобождалась. Это привело к тому, что занимаемая памятью служба потребляет доступную память сервера в течение нескольких дней с предсказуемыми результатами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...