web-dev-qa-db-fra.com

L'utilisation de 'var' affectera-t-elle les performances?

Un peu plus tôt, je posais une question à propos de pourquoi je vois tant d’exemples, utilisez le varkeyword et ai obtenu la réponse que, même s’il n’est nécessaire que pour les types anonymes, il est néanmoins utilisé pour écrire du code 'plus rapide'/plus facile et 'juste parce que'.

Après ce lien ("C # 3.0 - La variable n'est pas objec") J'ai vu que var est compilé jusqu'au type correct dans l'IL (vous le verrez au milieu de l'article) ).

Ma question est la suivante: combien de code IL utilise-t-il davantage, le cas échéant, avec le mot-clé var? Serait-il même proche d'un niveau mesurable sur les performances du code s'il était utilisé partout?

220
Jeff Keslinke

Il n'y a pas de code IL supplémentaire pour le mot clé var: l'IL résultant doit être identique pour les types non anonymes. Si le compilateur ne peut pas créer cet IL parce qu'il ne sait pas quel type vous avez l'intention d'utiliser, vous obtiendrez une erreur du compilateur.

Le seul truc est que var déduira un type exact dans lequel vous avez peut-être choisi un type Interface ou un type parent si vous deviez définir le type manuellement.


Mise à jour 8 ans plus tard

J'ai besoin de mettre à jour ceci car ma compréhension a changé. Je crois maintenant qu'il est possible que var affecte les performances dans le cas où une méthode renvoie une interface, mais vous auriez utilisé un type exact. Par exemple, si vous avez cette méthode:

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

Considérez ces trois lignes de code pour appeler la méthode:

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

Les trois compiler et exécuter comme prévu. Cependant, les deux premières lignes sont pas exactement identiques, et la troisième ligne correspondra à la seconde plutôt qu'à la première. Comme la signature de Foo() doit renvoyer un IList<int>, Le compilateur construira ainsi la variable bar3.

Du point de vue de la performance, la plupart du temps, vous ne le remarquerez pas. Cependant, il existe des situations où la performance de la troisième ligne peut ne pas être aussi rapide que celle de la première . Si vous continuez à utiliser la variable bar3, Il se peut que le compilateur ne puisse pas envoyer les appels de méthode de la même manière.

Notez qu'il est possible (probablement même) que la gigue puisse effacer cette différence, mais ce n'est pas garanti. En règle générale, vous devriez toujours considérer que var n'est pas un facteur en termes de performances. Ce n'est certainement pas du tout comme utiliser un dynamic variable. Mais dire que cela ne fait jamais une différence peut être exagéré.

303
Joel Coehoorn

Comme le dit Joel, le compilateur fonctionne à à la compilation quel type var devrait être, ce n'est en réalité qu'une astuce que le compilateur effectue pour enregistrer les séquences de touches, donc par exemple

var s = "hi";

est remplacé par

string s = "hi";

par le compilateur avant que tout IL soit généré. L'IL généré sera exactement le même que si vous aviez tapé une chaîne.

71
ljs

Comme personne n'a encore mentionné le réflecteur ...

Si vous compilez le code C # suivant:

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

Ensuite, utilisez un réflecteur dessus, vous obtenez:

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

La réponse n’est donc clairement pas liée aux performances d’exécution!

25
RichardOD

Pour la méthode suivante:

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

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

La sortie IL est la suivante:

        {
          .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
Rob

Donc, pour être clair, c'est un style de codage paresseux. Je préfère les types natifs, étant donné le choix; Je vais prendre un peu de "bruit" pour m'assurer d'écrire et de lire exactement ce que je pense être au moment du code/débogage. * haussement d'épaules *

15
ChrisH

Le compilateur C # déduit le vrai type de la variable var au moment de la compilation. Il n'y a pas de différence dans l'IL généré.

13
Michael Burr

Je ne pense pas que vous ayez bien compris ce que vous avez lu. Si le type correct est compilé, alors il n'y a pas pas de différence. Quand je fais ça:

var i = 42;

Le compilateur sait que c'est un int et génère du code comme si j'avais écrit

int i = 42;

Comme le message que vous avez lié, il est compilé dans le même type. Ce n'est pas une vérification à l'exécution ou autre chose nécessitant du code supplémentaire. Le compilateur détermine simplement quel type doit être et l’utilise.

8
jalf

Il n'y a aucun coût de performance d'exécution lié à l'utilisation de var. Cependant, je soupçonne qu'il y a un coût de performance de compilation car le compilateur doit déduire le type, bien que ce soit probablement négligeable.

5
Brian Rudolph

Si le compilateur peut effectuer des déductions de type automatiques, il n'y aura aucun problème de performances. Les deux vont générer le même code

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

cependant, si vous construisez le type de manière dynamique (LINQ ...), alors var est votre seule question et il existe un autre mécanisme à comparer afin de dire quelle est la pénalité.

3
alex

J'utilise toujours Word var dans des articles Web ou des écrits de guides.

La largeur de l'éditeur de texte de l'article en ligne est petite.

Si j'écris ceci:

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

Vous verrez que le texte de pré-code rendu ci-dessus est trop long et sort de la boîte, il est masqué. Le lecteur doit faire défiler vers la droite pour voir la syntaxe complète.

C'est pourquoi j'utilise toujours le mot clé var dans les articles écrits sur le Web.

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

L'ensemble du code pré-rendu correspond à l'écran.

En pratique, pour déclarer un objet, j'utilise rarement var, je compte sur intellisense pour déclarer un objet plus rapidement.

Exemple:

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

Mais, pour renvoyer un objet depuis une méthode, j'utilise var pour écrire du code plus rapidement.

Exemple:

var coolObject = GetCoolObject(param1, param2);
3
mjb

"var" fait partie de ces choses que les gens aiment ou détestent (comme les régions). Bien que, contrairement aux régions, var soit absolument nécessaire lors de la création de classes anonymes.

Pour moi, var est logique lorsque vous créez un objet directement, par exemple:

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

Cela étant dit, vous pouvez facilement faire:

Dictionary<string, string> dict = New et intellisense combleront le reste pour vous ici.

Si vous souhaitez uniquement travailler avec une interface spécifique, vous ne pouvez pas utiliser var si la méthode que vous appelez ne renvoie pas directement l'interface.

Resharper semble être sur le point d'utiliser "var" partout, ce qui peut pousser plus de gens à le faire de cette façon. Mais je suis plutôt d'accord sur le fait qu'il est plus difficile à lire si vous appelez une méthode et que le nom renvoyé n'est pas évident.

le var lui-même ne ralentit pas les choses, mais il ya une mise en garde à laquelle peu de gens pensent. Si vous faites var result = SomeMethod();, alors le code qui s’en suit attend un résultat quelconque dans lequel vous appelez différentes méthodes ou propriétés, ou quoi que ce soit. Si SomeMethod() a changé sa définition en un autre type mais qu'il respectait toujours le contrat que l'autre code attendait, vous venez de créer un bug vraiment méchant (si aucun test d'unité/d'intégration, bien sûr).

2
Daniel Lorenz

Cela dépend de la situation, si vous essayez d’utiliser ce code ci-dessous.

L'expression est convertie en "OBJECT" et diminue tellement la performance, mais c'est un problème isolé.

CODE:

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

Résultats ci-dessus avec 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();
}

Si vous souhaitez exécuter ce code, utilisez le code ci-dessous et obtenez la différence de temps.

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

Cordialement

0
Silvio Garcez