Teoretycznie metoda statyczna powinna działać nieco lepiej niż metoda instancji, przy czym wszystkie inne this
parametry powinny być takie same, ze względu na dodatkowy ukryty parametr.
W praktyce robi to tak małą różnicę, że będzie ukryte w szumie różnych decyzji kompilatora. (W związku z tym dwie osoby mogą „udowodnić” jedną lepiej niż drugą z różnymi wynikami). Nie tylko dlatego, że this
jest zwykle przekazywany w rejestrze i często znajduje się w tym rejestrze na początku.
Ten ostatni punkt oznacza, że teoretycznie powinniśmy spodziewać się statycznej metody, która przyjmuje obiekt jako parametr i robi coś z nim, będzie nieco gorsza niż odpowiednik jako instancja tego samego obiektu. Znowu jednak różnica jest tak niewielka, że gdybyś próbował ją zmierzyć, prawdopodobnie skończyłbyś mierzeniem innej decyzji kompilatora. (Zwłaszcza, że prawdopodobieństwo, że odniesienie to będzie w rejestrze przez cały czas, jest również dość wysokie).
Rzeczywiste różnice w wydajności sprowadzą się do tego, czy sztucznie masz obiekty w pamięci, aby zrobić coś, co naturalnie powinno być statyczne, czy też splątasz łańcuchy przekazywania obiektów w skomplikowany sposób, aby zrobić to, co powinno naturalnie być instancją.
Stąd dla numeru 1. Kiedy utrzymywanie stanu nie jest problemem, zawsze lepiej być statycznym, ponieważ statystyka służy temu . Nie jest to problem z wydajnością, chociaż istnieje ogólna zasada ładnego grania z optymalizacjami kompilatora - jest bardziej prawdopodobne, że ktoś zadał sobie trud optymalizacji przypadków, które pojawiają się przy normalnym użyciu, niż tych, które wymyślają dziwne użycie.
Numer 2. Nie ma różnicy. Dla każdego członka istnieje pewna kwota kosztu na klasę, która zależy zarówno od ilości metadanych, ile kodu znajduje się w rzeczywistym pliku DLL lub EXE, jak i od tego, ile będzie w nim utraconego kodu. To jest to samo, czy jest to instancja, czy statyczna.
W przypadku pozycji 3 this
jest tak this
samo. Jednak uwaga:
this
Parametr jest przekazywana w danym rejestrze. Podczas wywoływania metody instancji w tej samej klasie, prawdopodobnie będzie ona już w tym rejestrze (chyba że została ukryta i rejestr używany z jakiegoś powodu), a zatem nie jest wymagana żadna akcja, aby ustawić this
to, co należy ustawić . Dotyczy to w pewnym stopniu np. Pierwszych dwóch parametrów metody, która jest pierwszymi dwoma parametrami wywołania, które wykonuje.
Ponieważ będzie jasne, że this
nie jest to null, w niektórych przypadkach może to służyć do optymalizacji połączeń.
Ponieważ będzie jasne, że this
nie jest null, może to ponownie zwiększyć wydajność wywołań metod wbudowanych, ponieważ kod utworzony w celu sfałszowania wywołania metody może pominąć niektóre sprawdzenia wartości null, których i tak może potrzebować.
To powiedziawszy, czeki zerowe są tanie!
Warto zauważyć, że ogólne metody statyczne działające na obiekcie, a nie metody instancji, mogą zmniejszyć niektóre koszty omówione na stronie http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- związane z narzutami / w przypadku, gdy dana statyczna nie jest wywoływana dla danego typu. Jak to ujął: „Na marginesie okazuje się, że metody rozszerzające to świetny sposób, aby generyczne abstrakcje były bardziej opłacalne”.
Należy jednak pamiętać, że dotyczy to tylko tworzenia instancji innych typów używanych przez metodę, które w innym przypadku nie istnieją. W związku z tym tak naprawdę nie ma zastosowania w wielu przypadkach (inna metoda instancji używała tego typu, jakiś inny kod w innym miejscu używał tego typu).
Podsumowanie:
- Przeważnie koszty wydajności instancji w porównaniu ze statycznymi są poniżej nieistotnych.
- Jakie są koszty, generalnie pojawią się, gdy na przykład nadużyjesz statyczności lub odwrotnie. Jeśli nie podejmiesz decyzji o wyborze między statycznym a instancją, masz większe szanse na uzyskanie prawidłowego wyniku.
- Istnieją rzadkie przypadki, w których statyczne metody ogólne innego typu powodują utworzenie mniejszej liczby typów niż metody generyczne instancji, co może czasami mieć niewielką korzyść, gdy są rzadko używane (i „rzadko” odnosi się do typów, z którymi są używane w żywotność aplikacji, a nie jak często jest wywoływana). Kiedy już dowiesz się, o czym mówi w tym artykule, zobaczysz, że i tak jest to w 100% nieistotne dla większości decyzji statycznych i instancji. Edycja: I przeważnie ma ten koszt tylko z ngen, a nie z jittedem.
Edycja: uwaga na temat tego, jak tanie są czeki zerowe (które twierdziłem powyżej). Większość sprawdzeń null w .NET w ogóle nie sprawdza wartości null, raczej kontynuuje to, co zamierzali zrobić, zakładając, że zadziała, a jeśli zdarzy się wyjątek dostępu, zostanie zamieniony w plik NullReferenceException
. W związku z tym, głównie wtedy, gdy koncepcyjnie kod C # obejmuje sprawdzenie wartości null, ponieważ uzyskuje dostęp do elementu członkowskiego wystąpienia, koszt, jeśli się powiedzie, wynosi w rzeczywistości zero. Wyjątkiem byłyby niektóre wbudowane wywołania (ponieważ chcą zachowywać się tak, jakby dzwonili do członka instancji) i po prostu uderzają w pole, aby wywołać to samo zachowanie, więc są również bardzo tanie i i tak często można je pominąć (np. jeśli pierwszy krok metody obejmował dostęp do pola w takiej postaci).