Un peu plus tôt, je posais une question à propos de pourquoi je vois tant d’exemples, utilisez le var
keyword 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?
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.
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é.
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.
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!
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
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 *
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é.
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.
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.
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é.
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);
"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).
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