Zalety korzystania z prywatnych metod statycznych

209

Czy podczas tworzenia klasy z wewnętrznymi metodami prywatnymi, zwykle w celu ograniczenia duplikacji kodu, które nie wymagają użycia pól instancji, istnieją zalety związane z wydajnością lub pamięcią w przypadku deklarowania metody jako statycznej?

Przykład:

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;
}

Czy istnieje korzyść z deklarowania metod GetInnerXml () jako statycznych? Proszę o brak opinii, mam opinię.

NerdFury
źródło

Odpowiedzi:

221

Ze strony reguły FxCop na ten temat:

Po oznaczeniu metod jako statycznych kompilator wyemituje nie wirtualne witryny wywołujące dla tych członków. Emitowanie nie-wirtualnych witryn wywołań zapobiegnie sprawdzaniu w czasie wykonywania każdego połączenia, które zapewnia, że ​​wskaźnik bieżącego obiektu nie jest zerowy. Może to spowodować wymierny wzrost wydajności kodu wrażliwego na wydajność. W niektórych przypadkach brak dostępu do bieżącej instancji obiektu oznacza problem z poprawnością.

Scott Dorman
źródło
37
Dodałbym również, że klauzula „statyczna” nie szkodzi i zawiera już „dokumentację” zawierającą 1 słowo. Mówi ci, że ta metoda nie korzysta z żadnego elementu instancji, i otrzymujesz tę dokumentację prawie za darmo
frandevel
20
Chciałbym nawet powiedzieć: „Jeśli metoda nie potrzebuje dostępu do stanu (this), ustaw ją jako statyczną” jako ogólną zasadę.
DanMan
3
W trosce o równowagę warto zauważyć, że wiele osób jest generalnie przeciwnych metodom statycznym, ponieważ łamią polimorfizm i oznaczają, że obiekt nie może zostać unieruchomiony do testowania. na przykład patrz googletesting.blogspot.co.uk/2008/12/…
Andy
@ Andy - Dobra uwaga. Jednym ze sposobów narysowania linii byłoby sprawdzenie, czy metoda statyczna uzyskuje dostęp do czegokolwiek poza parametrami, które przekazujesz. Tak długo, jak jest to samodzielne w ten sposób, powinno być łatwe do przetestowania i nie ma potrzeby do niczego.
Neil
4
Wielu programistów nie zna „prywatnego statycznego”. Użyłem go we wspólnej bazie kodu mojego zespołu i doprowadziło to do zamieszania. W zamian zapewnia bardzo niewielkie korzyści. Moglibyśmy edukować wszystkich członków zespołu, w tym wszystkich przyszłych programistów utrzymujących kod, co to znaczy. Ale korzyść z zamiany prywatnej metody na prywatną statyczną jest tak niewielka (tj. Usunięcie zależności od danych instancji), że nie jest to warte wysiłku i zamieszania. Ta metoda ma już prywatny zasięg. To dziwactwo językowe, które tak naprawdę nie jest konieczne.
Curtis Yallop,
93

Kiedy piszę zajęcia, większość metod dzieli się na dwie kategorie:

  • Metody wykorzystujące / zmieniające stan bieżącej instancji.
  • Metody pomocnicze, które nie używają / nie zmieniają bieżącego stanu obiektu, ale pomagają mi w obliczaniu wartości potrzebnych gdzie indziej.

Metody statyczne są przydatne, ponieważ po prostu patrząc na jego podpis, wiesz, że wywołanie nie używa ani nie modyfikuje stanu bieżącej instancji.

Weź ten przykład:

Biblioteka klasy publicznej
{
    prywatny statyczny Book findBook (Lista <Book> książek, tytuł ciągu)
    {
        // kod idzie tutaj
    }
}

Jeśli instancja stanu biblioteki kiedykolwiek się popsuła, a ja próbuję dowiedzieć się, dlaczego, mogę wykluczyć winowajcę ze względu na jego podpis.

Staram się komunikować jak najwięcej z podpisem metody lub funkcji i jest to doskonały sposób na zrobienie tego.

Neil
źródło
1
Rodzaj deklaracji const-method w C ++, prawda?
anhoppe
Tak - to kolejny dobry sposób na użycie języka w celu uproszczenia rzeczy poprzez ograniczenie tego, co może pójść nie tak.
Neil
To niekoniecznie prawda. Załóżmy, że Libraryma pole instancji List<Book> _booksprzechowywać go Książki (nie jak chcesz zaprojektować Libraryklasę prawdopodobnie ale w / e), i przekazuje tę listę findBook, i który wywołuje metody statyczne books.Clear()albo books.Reverse()i tak dalej. Jeśli dasz statycznej metodzie dostęp do odwołania do jakiegoś stanu zmiennego, wtedy ta statyczna metoda może bardzo zepsuć twój stan.
sara,
1
Prawdziwe. W takim przypadku sygnatura pokazałaby nam, że ta metoda miała dostęp do instancji biblioteki (i możliwość mutowania).
Neil
W przypadku praktycznie każdego konstruktu ochronnego, którego moglibyśmy użyć, istnieje pewien sposób, aby go podważyć. Ale korzystanie z nich jest nadal mądre i pomaga popchnąć nas we właściwym kierunku, ku „otchłani sukcesu”.
Neil,
81

Wywołanie metody statycznej generuje instrukcję wywołania w języku pośrednim Microsoft (MSIL), podczas gdy wywołanie metody instancji generuje instrukcję callvirt, która sprawdza również odwołania do obiektów zerowych. Jednak przez większość czasu różnica między nimi nie jest znacząca.

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

Marek Takac
źródło
15

Tak, kompilator nie musi przekazywać niejawnego thiswskaźnika do staticmetod. Nawet jeśli nie użyjesz go w metodzie instancji, nadal jest przekazywany.

Kent Boogaart
źródło
Jak to się wiąże z przewagą wydajności lub pamięci w czasie wykonywania?
Scott Dorman,
11
Przekazywanie dodatkowego parametru oznacza, że ​​CPU musi wykonać dodatkową pracę, aby umieścić ten parametr w rejestrze i wcisnąć go na stos, jeśli metoda instancji wywoła inną metodę.
Kent Boogaart,
5

Będzie to nieco szybsze, ponieważ nie przekazano tego parametru (chociaż koszt wydajności wywołania metody jest prawdopodobnie znacznie większy niż oszczędność).

Powiedziałbym, że najlepszym powodem, dla którego mogę wymyślić prywatne metody statyczne, jest to, że nie możesz przypadkowo zmienić obiektu (ponieważ nie ma tego wskaźnika).

Bezpłatny GNU
źródło
4

To zmusza cię do zapamiętania, aby zadeklarować również elementy o zasięgu klasy, których funkcja używa również jako statyczne, co powinno oszczędzić pamięć tworzenia tych elementów dla każdej instancji.

Joel Coehoorn
źródło
To, że jest to zmienna o zasięgu klasowym, nie oznacza, że ​​powinna być statyczna.
Scott Dorman
3
Nie, ale jeśli jest używany metodą statyczną, MUSI być statyczny. Jeśli metoda nie była statyczna, być może nie uczyniono by członka klasy statycznym, a to spowodowałoby więcej pamięci używanej dla każdej instancji klasy.
Joel Coehoorn
2

Bardzo wolę, aby wszystkie prywatne metody były statyczne, chyba że tak naprawdę nie mogą być. Wolałbym następujące:

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;
    }
}

nad każdą metodą uzyskującą dostęp do pola instancji. Dlaczego to? Ponieważ ponieważ ten proces obliczania staje się bardziej złożony, a klasa kończy się na 15 metodach prywatnego pomocnika, NAPRAWDĘ chcę móc wyciągnąć je do nowej klasy, która zawiera semantycznie znaczący podzbiór kroków.

Kiedy MyClasspojawia się więcej zależności, ponieważ potrzebujemy logowania, a także musimy powiadomić serwis internetowy (proszę wybaczyć przykładowe przykłady), wtedy naprawdę pomocne jest łatwe sprawdzenie, jakie metody mają zależności.

Narzędzia takie jak R # pozwalają wyodrębnić klasę z zestawu prywatnych metod statycznych za pomocą kilku naciśnięć klawiszy. Spróbuj to zrobić, gdy wszystkie prywatne metody pomocnicze są ściśle powiązane z polem instancji, a zobaczysz, że może to być ból głowy.

sara
źródło
-3

Jak już wspomniano, metody statyczne mają wiele zalet. Jednak; pamiętaj, że będą żyć na stosie przez cały okres użytkowania aplikacji. Niedawno spędziłem dzień na śledzeniu wycieku pamięci w usłudze Windows ... przeciek został spowodowany przez prywatne metody statyczne w klasie, która zaimplementowała IDisposable i była konsekwentnie wywoływana z instrukcji using. Za każdym razem, gdy ta klasa została utworzona, pamięć była rezerwowana na stercie dla metod statycznych w klasie, niestety, gdy klasa została zutylizowana, pamięć dla metod statycznych nie była zwalniana. Spowodowało to, że ślad tej usługi zużył dostępną pamięć serwera w ciągu kilku dni z przewidywalnymi rezultatami.

James Haumann
źródło
4
To nie ma sensu. Sterta nigdy nie przechowuje pamięci kodu dla jakichkolwiek metod, statycznych lub innych. Sterty są dla instancji obiektów. Na stosie będą znajdować się dane do dowolnego wywołania dowolnej metody (w celu przechowywania pamięci dla parametrów, wartości zwracanej, lokalizacji lokalnych bez podnoszenia itp.), Ale wszystko to zniknie, gdy metoda zakończy wykonywanie.
Servy