Wcześniej zadałem pytanie, dlaczego widzę tak wiele przykładów używających var
słowa kluczowego i uzyskałem odpowiedź, że chociaż jest to konieczne tylko w przypadku typów anonimowych, to jednak jest ono używane, aby pisanie kodu było „szybsze” / łatwiejsze i „tylko dlatego”.
Podążając za tym linkiem („C # 3.0 - Var Is Not Objec”) zobaczyłem, że var
kompiluje się do właściwego typu w IL (zobaczycie go w połowie artykułu).
Moje pytanie brzmi: o ile więcej, jeśli w ogóle, kod IL wymaga użycia var
słowa kluczowego, a czy byłby nawet bliski mierzalnego poziomu wydajności kodu, gdyby był używany wszędzie?
c#
performance
variables
var
Jeff Keslinke
źródło
źródło
var
całą pewnością współpracują z „Znajdź wszystkie referencje” w Visual Studio 2019, więc jeśli kiedykolwiek był uszkodzony, został naprawiony. Ale mogę potwierdzić, że działa już w Visual Studio 2012, więc nie jestem pewien, dlaczego twierdziłeś, że to nie działa.var
nie będzie traktowany jako odniesienie,X
gdy użyjesz opcji „Znajdź wszystkie odniesienia”X
. Co ciekawe, jeśli używasz „Znajdź wszystkie odniesienia” navar
w tym piśmie, że będzie pokazać odniesień doX
(choć nadal nie będzie listavar
instrukcji). Dodatkowo, gdy kursor jest włączonyvar
, podświetli wszystkie wystąpieniaX
tego samego dokumentu (i odwrotnie).Odpowiedzi:
Nie ma dodatkowego kodu IL dla
var
słowa kluczowego: wynikowa IL powinna być identyczna dla typów nieanonimowych. Jeśli kompilator nie może utworzyć tej IL, ponieważ nie może dowiedzieć się, jakiego typu zamierzasz użyć, pojawi się błąd kompilatora.Jedyną sztuczką jest
var
ustalenie dokładnego typu, w którym mógłbyś wybrać typ interfejsu lub typ nadrzędny, jeśli ustawiłeś typ ręcznie.Zaktualizuj 8 lat później
Muszę to zaktualizować, ponieważ zmieniło się moje rozumienie. Teraz uważam, że może mieć to
var
wpływ na wydajność w sytuacji, gdy metoda zwraca interfejs, ale użyłbyś dokładnego typu. Na przykład, jeśli masz tę metodę:Rozważ te trzy linie kodu, aby wywołać metodę:
Wszystkie trzy kompilują się i wykonują zgodnie z oczekiwaniami. Jednak pierwsze dwie linie nie są dokładnie takie same, a trzecia linia będzie pasować do drugiej, a nie pierwszej. Ponieważ podpis
Foo()
ma zwrócić anIList<int>
, w ten sposób kompilator zbudujebar3
zmienną.Z punktu widzenia wydajności przeważnie nie zauważysz. Są jednak sytuacje, w których wydajność trzeciej linii może nie być tak szybka jak wydajność pierwszej . W miarę dalszego używania
bar3
zmiennej kompilator może nie być w stanie wywołać wywołań metod w ten sam sposób.Pamiętaj, że możliwe (prawdopodobnie nawet) drgania będą w stanie usunąć tę różnicę, ale nie jest to gwarantowane. Ogólnie rzecz biorąc, powinieneś nadal uważać
var
się za czynnik bez znaczenia pod względem wydajności. Z pewnością wcale nie jest tak, jak przy użyciudynamic
zmiennej. Ale stwierdzenie, że to nigdy nie robi różnicy, może być przesadzeniem.źródło
var i = 42;
(infers type is int) NIE jest identyczny zlong i = 42;
. Tak więc w niektórych przypadkach możesz przyjmować błędne założenia dotyczące wnioskowania o typie. Może to powodować nieuchwytne błędy czasu wykonania przypadku / krawędzi, jeśli wartość nie będzie pasować. Z tego powodu dobrym pomysłem może być jawne określenie, gdy wartość nie ma jawnego typu. Na przykładvar x = new List<List<Dictionary<int, string>()>()>()
byłby do przyjęcia, alevar x = 42
jest nieco niejednoznaczny i powinien być zapisany jakoint x = 42
. Ale każdemu z nich ...var x = 42;
nie jest dwuznaczny. Literały całkowite są tego typuint
. Jeśli chcesz dosłownie długo piszeszvar x = 42L;
.Foo
zwrócił aList
, a nie anIList
, wówczas wszystkie trzy linie by się skompilowały, ale trzecia linia zachowałaby się jak pierwsza linia , a nie druga.Jak mówi Joel, kompilator sprawdza w czasie kompilacji, jaki typ zmiennej powinien być, w rzeczywistości jest to tylko sztuczka, którą kompilator wykonuje, aby zapisać naciśnięcia klawiszy, więc na przykład
zostaje zastąpiony przez
przez kompilator przed wygenerowaniem jakiejkolwiek IL. Wygenerowana IL będzie dokładnie taka sama, jakbyś wpisał ciąg.
źródło
Jak nikt jeszcze nie wspomniał o odbłyśniku ...
Jeśli skompilujesz następujący kod C #:
Następnie użyj na nim reflektora, otrzymasz:
Zatem odpowiedź wyraźnie nie ma wpływu na wydajność środowiska uruchomieniowego!
źródło
Dla następującej metody:
Wyjście IL jest następujące:
źródło
Kompilator C # określa prawdziwy typ
var
zmiennej w czasie kompilacji. Nie ma różnicy w wygenerowanej IL.źródło
Tak więc, dla jasności, jest to leniwy styl kodowania. Wolę typy rodzime, biorąc pod uwagę wybór; Wezmę ten dodatkowy „szum”, aby upewnić się, że piszę i czytam dokładnie to, co myślę, że jestem w czasie kodowania / debugowania. * wzrusza ramionami *
źródło
var
w ogóle wpływa na wydajność; po prostu wyrażasz swoją opinię, czy ludzie powinni go używać.int
ponieważ nie może ona automatycznie przekonwertowaćfloat
, ale to dokładnie to samo, co by się stało, gdybyś wyraźnie użył,int
a następnie zmienił nafloat
. W każdym razie twoja odpowiedź wciąż nie odpowiada na pytanie „czy używanievar
wpływa na wydajność?” (szczególnie jeśli chodzi o wygenerowaną IL)Nie sądzę, żebyś właściwie zrozumiał, co czytasz. Jeśli zostanie skompilowany do odpowiedniego typu, to nie ma żadnej różnicy. Kiedy to zrobię:
Kompilator wie, że to int i generuje kod tak, jakbym napisał
Jak mówi post, do którego prowadzi link, kompiluje się do tego samego typu. To nie jest kontrola czasu wykonywania ani nic innego wymagającego dodatkowego kodu. Kompilator po prostu domyśla się, jaki musi być typ, i używa tego.
źródło
Korzystanie z var nie wiąże się z żadnymi kosztami wydajności. Podejrzewam jednak, że wystąpiłby koszt wydajności kompilacji, ponieważ kompilator musi wnioskować o typie, chociaż najprawdopodobniej będzie to nieistotne.
źródło
Jeśli kompilator może dokonywać automatycznego wnioskowania na temat typu, nie będzie żadnego problemu z wydajnością. Oba wygenerują ten sam kod
jeśli jednak konstruujesz typ dynamicznie (LINQ ...), to
var
jest twoje jedyne pytanie i istnieje inny mechanizm do porównania, aby powiedzieć, jaka jest kara.źródło
Zawsze używam słowa var w artykułach internetowych lub pismach przewodników.
Szerokość edytora tekstowego artykułu online jest niewielka.
Jeśli to napiszę:
Zobaczysz, że powyższy renderowany tekst przed kodem jest zbyt długi i wypływa z pudełka, zostaje ukryty. Czytnik musi przewinąć w prawo, aby zobaczyć pełną składnię.
Dlatego zawsze używam słowa kluczowego var w pismach artykułów internetowych.
Cały renderowany kod wstępny po prostu mieści się na ekranie.
W praktyce do deklarowania obiektu rzadko używam var, polegam na inteligencji, aby szybciej deklarować obiekt.
Przykład:
Ale do zwracania obiektu z metody używam var do szybszego pisania kodu.
Przykład:
źródło
„var” to jedna z tych rzeczy, które ludzie lubią lub nienawidzą (jak regiony). Chociaż, w przeciwieństwie do regionów, var jest absolutnie konieczne przy tworzeniu anonimowych klas.
Dla mnie var ma sens, gdy tworzysz nowy obiekt bezpośrednio jak:
Biorąc to pod uwagę, możesz łatwo zrobić:
Dictionary<string, string> dict =
nowy i intellisense wypełnią resztę tutaj.Jeśli chcesz pracować tylko z określonym interfejsem, nie możesz używać var, chyba że wywoływana metoda bezpośrednio zwróci interfejs.
Resharper wydaje się być po stronie używania „var”, co może zmusić więcej ludzi do zrobienia tego w ten sposób. Ale zgadzam się, że trudniej jest przeczytać, jeśli wywołujesz metodę i nie jest oczywiste, co zwraca nazwa.
var sam nie spowalnia, ale jest jedno zastrzeżenie, o którym nie myśli wiele osób. Jeśli to zrobisz,
var result = SomeMethod();
kod po tym spodziewa się jakiegoś wyniku z powrotem w miejscu, w którym wywołasz różne metody, właściwości lub cokolwiek innego. JeśliSomeMethod()
zmienił definicję na inny typ, ale nadal spełniał warunki, których oczekiwał inny kod, po prostu stworzyłeś naprawdę paskudny błąd (oczywiście jeśli nie ma testów jednostkowych / integracyjnych).źródło
Zależy to od sytuacji, jeśli spróbujesz użyć tego kodu, poniżej.
Wyrażenie jest konwertowane na „OBIEKT” i znacznie obniża wydajność, ale jest to odizolowany problem.
KOD:
Powyższe wyniki z ILSPY.
Jeśli chcesz wykonać ten kod, użyj kodu poniżej i uzyskaj różnicę razy.
pozdrowienia
źródło