Metoda może być statyczna, ale czy powinna?


366

Resharper lubi wskazywać wiele funkcji na stronie asp.net, które można ustawić na statyczne. Czy to pomaga mi, jeśli sprawiam, że stają się statyczne? Czy powinienem uczynić je statycznymi i przenieść je do klasy użytkowej?


20
Czy Resharper tak naprawdę nie krzyczy „niska kohezja, niska kohezja”? czas sprawdzić, czy metoda naprawdę należy do tej klasy.
PK

Odpowiedzi:


245

Metody statyczne a metody instancji
10.2.5 Statyczne i instancyjne elementy specyfikacji języka C # wyjaśniają różnicę. Zasadniczo metody statyczne mogą zapewnić bardzo małe zwiększenie wydajności w stosunku do metod instancji, ale tylko w nieco ekstremalnych sytuacjach ( więcej informacji na ten temat można znaleźć w tej odpowiedzi ).

Reguła CA1822 w FxCop lub analizie kodu stwierdza:

„Po [oznaczeniu elementów jako statycznych] kompilator wyemituje do tych członków nie-wirtualne witryny wywołań, co zapobiegnie sprawdzaniu w czasie wykonywania każdego połączenia, które zapewnia, że ​​bieżący wskaźnik obiektu nie ma wartości zerowej. Może to spowodować wymierny wzrost wydajności dla kodu wrażliwego na wydajność. W niektórych przypadkach brak dostępu do bieżącej instancji obiektu oznacza problem z poprawnością. ”

Klasa użyteczności
Nie należy przenosić ich do klasy użyteczności, chyba że ma to sens w twoim projekcie. Jeśli metoda statyczna odnosi się do określonego typu, tak jak ToRadians(double degrees)metoda odnosi się do klasy reprezentującej kąty, sensowne jest, aby ta metoda istniała jako element statyczny tego typu (uwaga, jest to skomplikowany przykład do celów demonstracyjnych).


2
> kompilator będzie emitował nie wirtualne witryny wywołujące dla tych członków Właściwie to znaczy „kompilator może emitować ...”. Pamiętam coś o kompilatorze C # używającym callvirt zamiast call do obejścia potencjalnego błędu.
Jonathan Allen

24
Wycinam i wklejam go bezpośrednio z FxCop 1.36. Jeśli FxCop się myli, wystarczy.
Jeff Yates,

5
@ Maxim Nie jestem pewien, czy doceniam stwierdzenie „bzdury”; dość niegrzeczny sposób na podejście do nieznajomych. Punkt bazowy jest jednak ważny; Trochę zaktualizowałem rzeczy (to było 9 lat temu, więc nie pamiętam podstawy mojego pierwotnego roszczenia).
Jeff Yates,

10
@Maxim Twój punkt jest nieprawidłowy. Zapewniam cię, że 9 lat temu nie miałem dobrej oceny. Doceniam komentarze, które wskazują na błędy (lub zmiany, które je poprawiają), ale nie bądź niegrzeczny ani nie stawiaj nieuzasadnionych oczekiwań na innych. Nie nazywaj czegoś „bzdurą”; implikuje raczej zamiar oszukiwania niż uczciwości wobec błędu dobroci lub ignorancji. To nieuprzejme. Poświęcam swój czas na pomoc tutaj i to naprawdę jest bezcelowe, gdy jest traktowane z lekceważeniem. Nie mów mi, co mnie obraża - to mój wybór, a nie twój. Dowiedz się, jak wyrazić swoje zdanie z szacunkiem i uczciwością. Dziękuję Ci.
Jeff Yates

2
@Maksymalne Podczas gdy delegaci nie są zapisywani obok każdej instancji, każda instancja klasy bezstanowej rzeczywiście zajmuje pewną pamięć na stercie, co jest bezużytecznym narzutem. Zwykle tworzenie instancji usług nie jest gorącą ścieżką w aplikacji, ale jeśli twoja aplikacja konstruuje wiele z tych obiektów, będzie generować presję GC, której można by uniknąć po prostu stosując metody statyczne. Pierwotne twierdzenie OP, że w ekstremalnych sytuacjach metody statyczne zapewniają przewagę wydajności nad przypadkami bezstanowymi, zostało odpowiednio dopracowane i aktualne.
Asad Saeeduddin

259

Wydajność, zanieczyszczenie przestrzeni nazw itp. Są moim zdaniem drugorzędne. Zadaj sobie pytanie, co jest logiczne. Czy metoda logicznie działa na instancji typu, czy jest związana z samym typem? Jeśli jest to ten drugi, uczyń go metodą statyczną. Przenieś go do klasy użyteczności tylko, jeśli jest powiązany z typem, który nie jest pod twoją kontrolą.

Czasami istnieją metody, które działają logicznie na przykład, ale nie zdarzają się użycie dowolnego stanu instancji jest jeszcze . Na przykład, jeśli budujesz system plików i masz pojęcie katalogu, ale jeszcze go nie zaimplementowałeś, możesz napisać właściwość zwracającą rodzaj obiektu systemu plików, i zawsze będzie to po prostu „plik” - ale jest on logicznie powiązany z instancją, a zatem powinna być metodą instancji. Jest to również ważne, jeśli chcesz uczynić metodę wirtualną - twoja konkretna implementacja może nie wymagać stanu, ale klasy pochodne mogą. (Na przykład pytanie kolekcji, czy jest to tylko do odczytu - być może nie zaimplementowałeś jeszcze tej formy tylko do odczytu, ale wyraźnie jest to właściwość samej kolekcji, a nie typu).


1
Sądzę, że dobry liniowiec powinien mieć opcję ograniczenia wiadomości do metod innych niż wirtualne, ponieważ bardzo często metoda klasy podstawowej praktycznie nic nie robi. Metody zastępowania zwykle coś robią, ale nie zawsze. Czasami przydatne jest posiadanie klasy dla czegoś takiego jak pusty iEnumerable, którego metody zasadniczo ignorują instancję, ale gdy instancja jest wymagana do wybrania odpowiedniej metody do użycia.
supercat

2
„Czasami istnieją metody, które logicznie działają na instancję, ale nie wykorzystują jeszcze żadnego stanu instancji. Na przykład„ Podobało mi się korzystanie z „na przykład” w tej instancji.
PaulBinder

56

Oznaczenie metody jako staticwewnątrz klasy sprawia, że ​​oczywiste jest, że nie korzysta ona z żadnych elementów instancji, co może być pomocne przy przeglądaniu kodu.

Nie musisz koniecznie przenosić go do innej klasy, chyba że ma być dzielony przez inną klasę, która jest równie ściśle powiązana pod względem koncepcyjnym.


22

Jestem pewien, że tak się nie dzieje w twoim przypadku, ale jeden „nieprzyjemny zapach”, który widziałem w jakimś kodzie, który musiałem cierpieć z powodu utrzymywania stosowanej metody wielu statycznych metod.

Niestety były to metody statyczne, które zakładały określony stan aplikacji. (dlaczego, na pewno będziemy mieć tylko jednego użytkownika na aplikację! Dlaczego klasa User nie śledzi tego w zmiennych statycznych?) Były to chwalone sposoby dostępu do zmiennych globalnych. Mieli także konstruktory statyczne (!), Które prawie zawsze są złym pomysłem. (Wiem, że jest kilka rozsądnych wyjątków).

Jednak metody statyczne są dość przydatne, gdy uwzględniają logikę domeny, która tak naprawdę nie zależy od stanu instancji obiektu. Mogą sprawić, że Twój kod będzie znacznie bardziej czytelny.

Tylko upewnij się, że umieszczasz je we właściwym miejscu. Czy metody statyczne ingerują w stan wewnętrzny innych obiektów? Czy można uzasadnić, że ich zachowanie należy do jednej z tych klas? Jeśli nie rozdzielasz problemów w odpowiedni sposób, możesz mieć problemy z bólem głowy później.


4
Twój problem dotyczy pól / właściwości statycznych, a nie metod statycznych.
Asad Saeeduddin

10

To jest interesujące przeczytać:

http://thecuttingledge.com/?p=57

ReSharper tak naprawdę nie sugeruje, aby twoja metoda była statyczna. Powinieneś zadać sobie pytanie, dlaczego ta metoda jest w tej klasie, w przeciwieństwie do, powiedzmy, jednej z klas, która pojawia się w jej podpisie ...

ale oto, co mówi dokumentacja resharper: http://confluence.jetbrains.net/display/ReSharper/Member+can+be+made+static


2
Myślę, że ten punkt jest niedoceniany. To narzędzie naprawdę mówi ci, że metoda działa tylko na niektórych członkach innych klas. Jeśli jest to jakiś obiekt polecenia (lub „przypadek użycia” lub „interactor”), kto odpowiada za manipulowanie innymi obiektami, nie ma sprawy. Jednak jeśli manipuluje tylko jedną inną klasą, która brzmi bardzo podobnie do Feature Envy .
Greg

9

Wystarczy dodać do @Jason prawdą jest odpowiedź , to ważne jest, aby uświadomić sobie, że tylko wprowadzenie „static” na metodzie nie gwarantuje, że metoda będzie „czysty”. Będzie bezstanowy w odniesieniu do klasy, w której jest zadeklarowany, ale może również uzyskiwać dostęp do innych „statycznych” obiektów, które mają stan (konfiguracja aplikacji itp.), Nie zawsze może to być zła rzecz, ale jeden z powodów, dla których Osobiście wolę metody statyczne, gdy tylko mogę, że jeśli są czyste, możesz je testować i uzasadniać w izolacji, bez martwienia się o stan otoczenia.


6

Powinieneś robić to, co jest najbardziej czytelne i intuicyjne w danym scenariuszu.

Argument wydajności nie jest dobry, z wyjątkiem najbardziej ekstremalnych sytuacji, ponieważ jedyne, co się faktycznie dzieje, to to, że jeden dodatkowy parametr ( this) jest wypychany na stos, na przykład metody.


6

W przypadku złożonej logiki w klasie znalazłem prywatne metody statyczne przydatne w tworzeniu logiki izolowanej, w której dane wejściowe instancji są wyraźnie określone w sygnaturze metody i nie mogą wystąpić żadne skutki uboczne instancji. Wszystkie wyjścia muszą być przesyłane za pomocą wartości zwracanej lub parametrów out / ref. Podział skomplikowanej logiki na pozbawione skutków ubocznych bloki kodu może poprawić czytelność kodu i zaufanie zespołu programistów do niego.

Z drugiej strony może to prowadzić do zanieczyszczenia klasy przez rozprzestrzenianie się metod użyteczności. Jak zwykle, logiczne nazewnictwo, dokumentacja i spójne stosowanie konwencji kodowania zespołu mogą to złagodzić.


5

ReSharper nie sprawdza logiki. Sprawdza tylko, czy metoda korzysta z elementów instancji. Jeśli metoda jest prywatna i wywoływana tylko przez (może tylko jedną) metodę instancji, jest to znak pozwalający jej zastosować metodę instancji.


3

Jeśli funkcje są współużytkowane na wielu stronach, możesz również umieścić je w podstawowej klasie strony, a następnie odziedziczyć po niej wszystkie strony asp.net korzystające z tej funkcji (a funkcje mogą być również statyczne).


3

Ustawienie statycznej metody oznacza, że ​​możesz wywoływać metodę spoza klasy bez uprzedniego tworzenia instancji tej klasy. Jest to pomocne podczas pracy z obiektami lub dodatkami dostawców zewnętrznych. Wyobraź sobie, że musisz najpierw utworzyć obiekt konsoli „con” przed wywołaniem con.Writeline ();


Java wymaga utworzenia instancji fabryki w celu utworzenia obiektu Console przed wywołaniem con.Writeline ().
ScottMichaud

2

Pomaga kontrolować zanieczyszczenie przestrzeni nazw.


8
W jaki sposób zrobienie statycznej metody pomaga uniknąć zanieczyszczenia przestrzeni nazw?
lockstock

1
Z doświadczenia, grupując metody w klasy metodami statycznymi, unikasz konieczności prefiksu wszystkich „torebek” luźnych funkcji, które mogą kolidować z innymi bibliotekami lub funkcjami wbudowanymi. W przypadku metod statycznych są one efektywnie rozmieszczane pod nazwą Class, np. Class.a_core_function( .. )vsa_core_function( .. )
lintuxvi

0

Po prostu moja tuppence: Dodanie wszystkich wspólnych metod statycznych do klasy narzędzi pozwala na dodanie

using static className; 

do instrukcji using, dzięki czemu kod jest szybszy do pisania i łatwiejszy do odczytania. Na przykład mam dużą liczbę tak zwanych „zmiennych globalnych” w odziedziczonym przeze mnie kodzie. Zamiast tworzyć zmienne globalne w klasie, która była klasą instancji, ustawiłem je wszystkie jako właściwości statyczne klasy globalnej. Wykonuje to zadanie, jeśli jest bałagan, i mogę po prostu odwoływać się do właściwości według nazwy, ponieważ mam już statyczną przestrzeń nazw.

Nie mam pojęcia, czy to dobra praktyka, czy nie. Mam tak wiele do nauczenia się o C # 4/5 i tyle starszego kodu do refaktoryzacji, że po prostu próbuję poprowadzić wskazówki od Roselyn.

Joey


0

Mam nadzieję, że już zrozumiałeś różnicę między metodami statycznymi a instancjami. Ponadto może być długa i krótka odpowiedź. Długie odpowiedzi są już dostarczane przez innych.

Moja krótka odpowiedź: Tak, możesz przekonwertować je na metody statyczne, jeśli sugeruje to Resharper. Nie ma w tym nic złego. Zamiast tego, ustawiając metodę na statyczną, faktycznie chronisz ją, aby niepotrzebnie nie przypisywać żadnych elementów instancji do tej metody. W ten sposób możesz osiągnąć zasadę OOP „ Minimalizuj dostępność klas i członków ”.

Kiedy ReSharper sugeruje, że metodę instancji można przekonwertować na metodę statyczną, w rzeczywistości mówi: „Dlaczego ... ta metoda siedzi w tej klasie, ponieważ w rzeczywistości nie używa żadnego ze swoich stanów?” Daje to do myślenia. Następnie to Ty możesz zrozumieć potrzebę przeniesienia tej metody do statycznej klasy użyteczności, czy nie. Zgodnie z zasadami SOLID klasa powinna ponosić tylko jedną podstawową odpowiedzialność. W ten sposób możesz lepiej uporządkować swoje zajęcia. Czasami potrzebujesz niektórych metod pomocniczych, nawet w klasie instancji. W takim przypadku możesz zatrzymać ich w ramach pomocnika #region.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.