Преимущества использования частных статических методов
При создании класса с внутренними частными методами, обычно для уменьшения дублирования кода, не требующего использования каких-либо полей экземпляра, существуют ли преимущества производительности или памяти для объявления метода как статического?
Пример:
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() как статических? Никаких мнений, пожалуйста, у меня есть мнение.
Ответы
Ответ 1
На странице FxCop:
После того как вы пометили методы как статические, компилятор будет выдавать не виртуальные сайты вызовов этим членам. Испускание не виртуальных сайтов вызовов предотвратит проверку во время выполнения для каждого вызова, который гарантирует, что текущий указатель объекта не равен нулю. Это может привести к измеримому усилению производительности для кода, чувствительного к производительности. В некоторых случаях отказ в доступе к текущему экземпляру объекта представляет собой проблему корректности.
Ответ 2
Когда я пишу класс, большинство методов делятся на две категории:
- Способы, которые используют/изменяют текущее состояние экземпляра.
- Вспомогательные методы, которые не используют/не изменяют текущее состояние объекта, но помогают мне вычислять значения, которые мне нужны в другом месте.
Статические методы полезны, потому что, просто взглянув на свою подпись, вы знаете, что вызов не использует или не изменяет текущее состояние экземпляра.
Возьмем этот пример:
public class Library
{
private static Book findBook(List<Book> books, string title)
{
// code goes here
}
}
Если экземпляр состояния библиотеки когда-либо накручивается, и я пытаюсь понять, почему, я могу исключить findBook как виновника, как раз из его подписи.
Я стараюсь как можно больше общаться с сигнатурой метода или функции, и это отличный способ сделать это.
Ответ 3
Вызов статического метода генерирует инструкцию вызова на промежуточном языке Microsoft (MSIL), тогда как вызов метода экземпляра генерирует команду callvirt, которая также проверяет ссылки на нулевые объекты. Однако в большинстве случаев разница в производительности между ними невелика.
src: MSDN - http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.110).aspx
Ответ 4
Да, компилятору не нужно передавать неявный this
указатель на методы static
. Даже если вы не используете его в своем методе экземпляра, он все равно передается.
Ответ 5
Это будет немного быстрее, поскольку этот параметр не передан (хотя стоимость вызова вызова метода, вероятно, значительно больше, чем это сохранение).
Я бы сказал, что лучшая причина, по которой я могу думать о частных статических методах, заключается в том, что это означает, что вы не можете случайно изменить объект (поскольку там нет этого указателя).
Ответ 6
Это заставляет вас забывать также объявлять любые члены класса, которые функция использует как статические, а также сохранять память о создании этих элементов для каждого экземпляра.
Ответ 7
Я очень предпочитаю, чтобы все частные методы были статическими, если они действительно не могут быть. Я бы предпочел следующее:
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 #, позволяют извлекать класс из набора частных статических методов за несколько нажатий клавиш. Попробуйте сделать это, когда все частные вспомогательные методы тесно связаны с полем экземпляра, и вы увидите, что это может быть довольно головная боль.
Ответ 8
Как уже было сказано, существует множество преимуществ для статических методов. Однако; имейте в виду, что они будут жить в куче для жизни приложения. Недавно я провел день, отслеживая утечку памяти в службе Windows... утечка была вызвана частными статическими методами внутри класса, который реализовал IDisposable и последовательно вызывался из инструкции using. Каждый раз, когда этот класс был создан, память была зарезервирована в куче для статических методов в классе, к сожалению, когда класс был удален, память для статических методов не была выпущена. Это привело к тому, что память этой службы памяти потребляла доступную память сервера в течение нескольких дней с прогнозируемыми результатами.