Czy użycie 'var' wpłynie na wydajność?

Wcześniej zadałem pytanie o Dlaczego widzę, że tak wiele przykładów używa słowa kluczowego var i otrzymałem odpowiedź, że chociaż jest to konieczne tylko dla anonimowych typów, to jednak jest używane, aby pisanie kodu było "szybsze" /łatwiejsze i "tylko dlatego".

Po ten link ("C# 3.0 - Var isn 't Objec") widziałem, że {[0] } jest skompilowany do odpowiedniego typu w IL (zobaczysz to około połowy artykułu).

[[3]}moje pytanie brzmi, ile więcej, jeśli każdy, IL kod robi za pomocą var słowo kluczowe wziąć, i czy byłoby to nawet blisko do mierzalnego poziomu na wydajność kodu, jeśli był używany wszędzie?
Author: Community, 2008-12-10

12 answers

Nie ma dodatkowego kodu IL dla słowa kluczowego var: wynikowy kod IL powinien być identyczny dla typów nieanonimowych. Jeśli kompilator nie może utworzyć tego IL, ponieważ nie może dowiedzieć się, jakiego typu chcesz użyć, pojawi się błąd kompilatora.

Jedyną sztuczką jest to, że var wywnioskuje dokładny typ, w którym możesz wybrać interfejs lub typ rodzica, jeśli chcesz ustawić typ ręcznie.


Update 8 Years Later

Muszę zaktualizować to jako moje zrozumienie zmieniło się. Teraz wierzę, że var może mieć 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ę:

IList<int> Foo()
{
    return Enumerable.Range(0,10).ToList();
}

Rozważ te trzy linijki kodu, aby wywołać metodę:

List<int> bar1 = Foo();
IList<int> bar = Foo();
var bar3 = Foo();

Wszystkie trzy kompilują się i wykonują zgodnie z oczekiwaniami. Jednak pierwsze dwie linie są Nie dokładnie takie same, a trzecia linia będzie pasować do drugiej, a nie pierwszej. Ponieważ podpis z {[5] } zwraca IList<int>, w ten sposób kompilator zbuduje zmienną bar3.

Z punktu widzenia wydajności, przeważnie nie zauważysz. Jednak zdarzają się sytuacje, w których wydajność trzeciej linii może nie być tak szybka jak wydajność pierwszej . Ponieważ nadal używasz zmiennej bar3, kompilator może nie być w stanie wysyłać wywołań metod w ten sam sposób.

Zauważ, że jest możliwe (prawdopodobnie nawet), że jitter będzie w stanie to wymazać różnica, ale nie jest gwarantowana. Ogólnie rzecz biorąc, powinieneś nadal uważać var za czynnik nieuwzględniający wydajności. to z pewnością nie jest tak, jak przy użyciu dynamic zmiennej. Ale mówienie, że nigdy nie robi różnicy, może być przesadzone.

 319
Author: Joel Coehoorn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Jak mówi Joel, kompilator pracuje w compile-time Jaki powinien być Typ var, w rzeczywistości jest to tylko sztuczka, którą kompilator wykonuje, aby zapisać naciśnięcia klawiszy, więc na przykład

var s = "hi";

Zostaje zastąpiony przez

string s = "hi";

przez kompilator przed wygenerowaniem IL. Wygenerowany IL będzie dokładnie taki sam, jak gdybyś wpisał string.

 73
Author: ljs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 07:54:26

Jak nikt jeszcze nie wspomniał o reflektorze...

Jeśli skompilujesz następujący kod C#:

static void Main(string[] args)
{
    var x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Następnie użyj reflektora na nim, otrzymasz:

// Methods
private static void Main(string[] args)
{
    string x = "hello";
    string y = "hello again!";
    Console.WriteLine(x);
    Console.WriteLine(y);
}

Więc odpowiedź jest wyraźnie brak wydajności runtime hit!

 27
Author: RichardOD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-02 11:21:07

Dla następującej metody:

   private static void StringVsVarILOutput()
    {
        var string1 = new String(new char[9]);

        string string2 = new String(new char[9]);
    }

Wyjście IL Jest Takie:

        {
          .method private hidebysig static void  StringVsVarILOutput() cil managed
          // Code size       28 (0x1c)
          .maxstack  2
          .locals init ([0] string string1,
                   [1] string string2)
          IL_0000:  nop
          IL_0001:  ldc.i4.s   9
          IL_0003:  newarr     [mscorlib]System.Char
          IL_0008:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_000d:  stloc.0
          IL_000e:  ldc.i4.s   9
          IL_0010:  newarr     [mscorlib]System.Char
          IL_0015:  newobj     instance void [mscorlib]System.String::.ctor(char[])
          IL_001a:  stloc.1
          IL_001b:  ret
        } // end of method Program::StringVsVarILOutput
 17
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-22 20:15:20

Kompilator C# podaje prawdziwy typ zmiennej var w czasie kompilacji. Nie ma różnicy w generowanym IL.

 14
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-10 17:23:28

Żeby było jasne, to leniwy styl kodowania. Wolę natywne typy, biorąc pod uwagę wybór; wezmę ten dodatkowy kawałek "szumu", aby upewnić się, że piszę i czytam dokładnie to, co myślę, że jestem w czasie kodu/debugowania. * wzruszenie ramion *

 13
Author: ChrisH,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-20 15:29:44

Myślę, że nie zrozumiałeś właściwie tego, co przeczytałeś. Jeśli zostanie skompilowany do właściwego typu, to nie ma żadnej różnicy. Kiedy to robię:

var i = 42;

Kompilator zna to int i generuje kod tak, jakbym napisał

int i = 42;

Jak pisze post, do którego linkowałeś, zostaje skompilowany do tego samego typu. Nie jest to kontrola środowiska wykonawczego ani nic innego wymagającego dodatkowego kodu. Kompilator po prostu domyśla się, jaki musi być typ i używa go.

 8
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-10 17:30:41

Nie ma żadnych kosztów związanych z uruchomieniem var. Podejrzewałbym jednak, że będzie to koszt kompilacji, ponieważ kompilator musi wywnioskować Typ, choć najprawdopodobniej będzie to niedbałe.

 5
Author: Brian Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-10 17:41:10

Jeśli kompilator może wykonać automatyczne wnioskowanie typu, wtedy nie będzie żadnych problemów z wydajnością. Oba wygenerują ten sam kod

var    x = new ClassA();
ClassA x = new ClassA();

Jednakże, jeśli budujesz Typ dynamicznie (LINQ ...) wtedy var jest twoim jedynym pytaniem i jest inny mechanizm do porównania, aby powiedzieć, jaka jest kara.

 3
Author: bluish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-24 07:54:32

Zawsze używam słowa var w artykułach internetowych lub przewodnikach.

Szerokość edytora tekstu artykułu online jest niewielka.

Jeśli napiszę to:

SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

Zobaczysz, że powyżej renderowany tekst kodu pre jest zbyt długi i wypływa z pudełka, zostaje ukryty. Czytelnik musi przewijać w prawo, aby zobaczyć pełną składnię.

Dlatego zawsze używam słowa kluczowego var w pismach artykułów internetowych.

var coolClass = new SomeCoolNameSpace.SomeCoolClassName.SomeCoolSubClassName();

Cały renderowany kod pre mieści się w ekran.

W praktyce, do deklarowania obiektu rzadko używam var, polegam na intellisense, aby deklarować obiekt szybciej.

Przykład:

SomeCoolNamespace.SomeCoolObject coolObject = new SomeCoolNamespace.SomeCoolObject();

Ale do zwracania obiektu z metody używam var do szybszego pisania kodu.

Przykład:

var coolObject = GetCoolObject(param1, param2);
 3
Author: mjb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-17 01:59:00

"var" jest jedną z tych rzeczy, które ludzie kochają lub nienawidzą (jak regiony). Jednak, w przeciwieństwie do regionów, var jest absolutnie niezbędny przy tworzeniu anonimowych klas.

Dla mnie var ma sens, gdy tworzysz obiekt bezpośrednio taki jak:

var dict = new Dictionary<string, string>();

To jest powiedziane, można łatwo po prostu zrobić:

Dictionary<string, string> dict = nowy i intellisense wypełni resztę za Ciebie tutaj.

Jeśli chcesz pracować tylko z określonym interfejsem, nie możesz używać var, chyba że jesteś metodą wywołanie zwraca interfejs bezpośrednio.

Resharper wydaje się być po stronie używania "var", co może skłonić 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 jest zwracane przez nazwę.

Var sam w sobie nie spowalnia niczego, ale jest w tym jedno zastrzeżenie, o którym niewiele osób myśli. Jeśli zrobisz var result = SomeMethod(); to kod po tym oczekuje jakiegoś wyniku, gdzie można nazwać różne metody, właściwości czy cokolwiek. Jeśli SomeMethod() zmienił swoją definicję na inny typ, ale nadal spełniał kontrakt, którego oczekiwał drugi kod, po prostu stworzyłeś naprawdę paskudny błąd(jeśli oczywiście nie ma testów jednostkowych / integracyjnych).

 1
Author: Daniel Lorenz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-01 20:17:50

To zależy od sytuacji, jeśli spróbujesz użyć tego kodu poniżej.

Wyrażenie jest konwertowane na "obiekt" i zmniejsza wydajność, ale jest to odosobniony problem.

Kod:

public class Fruta
{
    dynamic _instance;

    public Fruta(dynamic obj)
    {
        _instance = obj;
    }

    public dynamic GetInstance()
    {
        return _instance;
    }
}

public class Manga
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
    public int MyProperty3 { get; set; }
}

public class Pera
{
    public int MyProperty { get; set; }
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
}

public class Executa
{
    public string Exec(int count, int value)
    {
        int x = 0;
        Random random = new Random();
        Stopwatch time = new Stopwatch();
        time.Start();

        while (x < count)
        {
            if (value == 0)
            {
                var obj = new Pera();
            }
            else if (value == 1)
            {
                Pera obj = new Pera();
            }
            else if (value == 2)
            {
                var obj = new Banana();
            }
            else if (value == 3)
            {
                var obj = (0 == random.Next(0, 1) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance());
            }
            else
            {
                Banana obj = new Banana();
            }

            x++;
        }

        time.Stop();
        return time.Elapsed.ToString();
    }

    public void ExecManga()
    {
        var obj = new Fruta(new Manga()).GetInstance();
        Manga obj2 = obj;
    }

    public void ExecPera()
    {
        var obj = new Fruta(new Pera()).GetInstance();
        Pera obj2 = obj;
    }
}

Powyżej wyniki z ILSPY.

public string Exec(int count, int value)
{
    int x = 0;
    Random random = new Random();
    Stopwatch time = new Stopwatch();
    time.Start();

    for (; x < count; x++)
    {
        switch (value)
        {
            case 0:
                {
                    Pera obj5 = new Pera();
                    break;
                }
            case 1:
                {
                    Pera obj4 = new Pera();
                    break;
                }
            case 2:
                {
                    Banana obj3 = default(Banana);
                    break;
                }
            case 3:
                {
                    object obj2 = (random.Next(0, 1) == 0) ? new Fruta(new Manga()).GetInstance() : new Fruta(new Pera()).GetInstance();
                    break;
                }
            default:
                {
                    Banana obj = default(Banana);
                    break;
                }
        }
    }
time.Stop();
return time.Elapsed.ToString();
}

Jeśli chcesz wykonać ten kod użyj poniższego kodu i uzyskaj różnicę czasów.

        static void Main(string[] args)
    {
        Executa exec = new Executa();            
        int x = 0;
        int times = 4;
        int count = 100000000;
        int[] intanceType = new int[4] { 0, 1, 2, 3 };

        while(x < times)
        {                
            Parallel.For(0, intanceType.Length, (i) => {
                Console.WriteLine($"Tentativa:{x} Tipo de Instancia: {intanceType[i]} Tempo Execução: {exec.Exec(count, intanceType[i])}");
            });
            x++;
        }

        Console.ReadLine();
    }

Pozdrawiam

 0
Author: Silvio Garcez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-24 01:00:28