Quelle est la différence entre dynamique (C # 4) et var?

199

J'avais lu une tonne d'articles sur ce nouveau mot-clé qui est livré avec C # v4, mais je ne pouvais pas faire la différence entre un "dynamique" et un "var".

Cet article m'a fait réfléchir, mais je ne vois toujours aucune différence.

Est-ce que vous pouvez utiliser "var" uniquement comme variable locale, mais dynamique à la fois local et global?

Pourriez-vous afficher du code sans mot clé dynamique, puis afficher le même code avec mot clé dynamique?

Ivan Prodanov
la source

Réponses:

455

varest de type statique - le compilateur et le runtime connaissent le type - ils vous font juste économiser du texte ... les éléments suivants sont 100% identiques:

var s = "abc";
Console.WriteLine(s.Length);

et

string s = "abc";
Console.WriteLine(s.Length);

Tout ce qui s'est passé, c'est que le compilateur a compris qu'il sdevait s'agir d'une chaîne (à partir de l'initialiseur). Dans les deux cas, il sait (dans l'IL) que cela s.Lengthsignifie la string.Lengthpropriété (instance) .

dynamicest une bête très différente; il est le plus similaire object, mais avec une répartition dynamique:

dynamic s = "abc";
Console.WriteLine(s.Length);

Ici, sest tapé comme dynamique . Il ne sait pas string.Length, parce qu'il ne sait pas quoi que ce soit au sujet sau moment de la compilation. Par exemple, les éléments suivants compileraient (mais ne s'exécuteraient pas) également:

dynamic s = "abc";
Console.WriteLine(s.FlibbleBananaSnowball);

Lors de l'exécution (uniquement), il vérifierait la FlibbleBananaSnowballpropriété - ne la trouverait pas et exploserait dans une pluie d'étincelles.

Avec dynamic, les propriétés / méthodes / opérateurs / etc sont résolus au moment de l'exécution , en fonction de l'objet réel. Très pratique pour parler à COM (qui peut avoir des propriétés d'exécution uniquement), au DLR ou à d'autres systèmes dynamiques, comme javascript.

Marc Gravell
la source
3
Une question intéressante serait de savoir s'il existe des ancêtres dynamiques de classes statiquement déclarées. Exemple: classe X {public int Y {get; set;}} dynamic (X) s = GetSpecialX (); Test de chaîne d'appel = sY; générerait une erreur de compilation car le compilateur connaît Y mais la chaîne test2 = sZ se compilerait correctement et serait vérifiée au moment de l'exécution. Je pourrais penser à beaucoup de valeur de ces classes semi-dynamiques!
mmmmmmmm
@rstevens - IIRC, vous pouvez ajouter un comportement dynamique via une interface (bien qu'il n'y ait pas de support de langage direct pour implémenter des types dynamiques en C # - seulement les consommer), donc ce n'est pas irréaliste ... oh le plaisir que nous pourrions avoir; - p
Marc Gravell
Bien qu'il soit important de noter qu'il varpeut parfois déduire des types qui pourraient ne pas être souhaités en raison de sous-types et de transtypages implicites. Autrement dit, varpeut avoir résolu un type statiquement différent de celui attendu lorsque des conversions implicites se produisent (notamment vers un type plus général, mais ce n'est pas limité à cela). Un exemple trivial est object x = ""vs var x = ""vs var x = "" as object, mais d'autres cas plus sournois (et réalistes) peuvent se produire et provoquer des bugs subtils.
Pour approfondir le bon exemple de Marc, dans le premier cas (de type statique), le compilateur sait exactement laquelle des nombreuses surchargesWriteLine appeler. Cette "liaison" se produit au moment de la compilation. Dans le cas de dynamic, le type de .Lengthdoit dynamicégalement l' être , et ce n'est qu'au moment de l'exécution qu'il est décidé quelle surcharge (le cas échéant) WriteLineconvient le mieux. La liaison se produit au moment de l'exécution.
Jeppe Stig Nielsen
4
Lorsque vous survolez le varmot clé dans Visual Studio, le type réel s'affiche qui est déduit. Vous indique que le type est connu au moment de la compilation.
Christian Fredh
56

Les variables déclarées avec var sont implicitement mais statiquement typées. Les variables déclarées avec dynamic sont typées dynamiquement. Cette capacité a été ajoutée au CLR afin de prendre en charge les langages dynamiques comme Ruby et Python.

Je dois ajouter que cela signifie que les déclarations dynamiques sont résolues au moment de l'exécution, les déclarations var sont résolues au moment de la compilation.

Hans Van Slooten
la source
42

Je vais expliquer la différence entre dynamique et var .

dynamic d1;
d1 = 1;
d1 = "http://mycodelogic.com";

Cela fonctionnera. le compilateur peut recréer le type de variable dynamique .
il crée d'abord le type sous forme d' entier et ensuite le compilateur recrée le type sous forme de chaîne
mais en cas de var

var v1;  // Compiler will throw error because we have to initialized at the time of declaration  
var v2 = 1; // Compiler will create v1 as **integer**
v2 = "Suneel Gupta"; // Compiler will throw error because, compiler will not recreate the type of variable 


Lors de l'utilisation du mot clé ' var ', le type est décidé par le compilateur au moment de la compilation, tandis que lors de l'utilisation du mot clé ' dynamic ', le type est décidé par le runtime.
mot-clé ' var ', une variable locale fortement implicitement typée pour laquelle le compilateur est capable de déterminer le type à partir de l'expression d'initialisation - très utile lors de la programmation LINQ.
Le compilateur ne possède aucune information sur le type dynamique de variable. donc le compilateur ne montrera aucune intelligence.
le compilateur a toutes les informations sur la valeur stockée du type var, donc le compilateur montrera de l'intelligence.
le type dynamique peut être passé comme argument de fonction et la fonction peut également renvoyer le type d'objet
Mais le type
var ne peut pas être passé comme argument de fonction et la fonction ne peut pas retourner le type d'objet. Ce type de variable peut fonctionner dans la portée où il a été défini.

Suneel Gupta
la source
14

var implique que la vérification de type statique (liaison anticipée) est appliquée. dynamique implique que la vérification de type dynamique (liaison tardive) est appliquée. En termes de code, considérez ce qui suit:

class Junk
{
    public void Hello()
    {
        Console.WriteLine("Hello");
    }
}

class Program
{
    static void Main(String[] args)
    {
        var a = new Junk();
        dynamic b = new Junk();

        a.Hello();

        b.Hello();
    }
}

Si vous compilez cela et inspectez les résultats avec ILSpy, vous constaterez que le compilateur a ajouté du code de liaison tardive qui gérera l'appel à Hello () de b, alors que, car une liaison précoce a été appliquée à a, a est capable d'appeler Hello () directement.

par exemple (démontage ILSpy)

using System;
namespace ConsoleApplication1
{
    internal class Junk
    {
        public void Hello()
        {
            Console.WriteLine("Hello");
        }
    }
}

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApplication1
{
    internal class Program
    {
        [CompilerGenerated]
        private static class <Main>o__SiteContainer0
        {
            public static CallSite<Action<CallSite, object>> <>p__Site1;
        }
        private static void Main(string[] args)
        {
            Junk a = new Junk();      //NOTE: Compiler converted var to Junk
            object b = new Junk();    //NOTE: Compiler converted dynamic to object
            a.Hello();  //Already Junk so just call the method.

                          //NOTE: Runtime binding (late binding) implementation added by compiler.
            if (Program.<Main>o__SiteContainer0.<>p__Site1 == null)
            {
                Program.<Main>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Hello", null, typeof(Program), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
                }));
            }
            Program.<Main>o__SiteContainer0.<>p__Site1.Target(Program.<Main>o__SiteContainer0.<>p__Site1, b);
        }
    }
}

La meilleure chose que vous puissiez faire pour découvrir la différence est de vous écrire une petite application console comme celle-ci et de la tester vous-même avec ILSpy.

Matthew Layton
la source
excellent exemple de base sur la façon dont IL les traite tous les deux après la compilation. Merci.
Kings
12

Une grande différence - vous pouvez avoir un type de retour dynamique.

dynamic Foo(int x)
{
    dynamic result;

    if (x < 5)
      result = x;
    else
      result = x.ToString();

    return result;
}
user2382351
la source
10

Voici un exemple simple qui montre la différence entre Dynamic (4.0) et Var

dynamic  di = 20;
dynamic ds = "sadlfk";
var vi = 10;
var vsTemp= "sdklf";

Console.WriteLine(di.GetType().ToString());          //Prints System.Int32
Console.WriteLine(ds.GetType().ToString());          //Prints System.String
Console.WriteLine(vi.GetType().ToString());          //Prints System.Int32
Console.WriteLine(vsTemp.GetType().ToString());      //Prints System.String

**ds = 12;**   //ds is treated as string until this stmt now assigning integer.

Console.WriteLine(ds.GetType().ToString());          **//Prints System.Int32**

**vs = 12**; //*Gives compile time error* - Here is the difference between Var and Dynamic. var is compile time bound variable.

Shiva Mamidi

Shiva Mamidi
la source
2
Mon impression est que la présence de **caractères dans l'exemple de code est destinée à indiquer uniquement l'accent et n'est pas destinée à faire partie du vrai code de travail.
DavidRR
7

var est juste un raccourci pour une déclaration de type normal, où vous laissez le compilateur deviner le type correct.

dynamic est un nouveau type (statique), où toutes les vérifications sont effectuées au moment de l'exécution, et non par le compilateur.

gimel
la source
4

Le type d'une variable déclarée avec var est déterminé par le compilateur, c'est un raccourci pour spécifier le nom du type, rien de plus.

Quelle que soit la dynamique déterminée lors de l'exécution, le compilateur n'a aucune idée du type réel et tous les accès aux méthodes / champs / propriétés avec cette variable seront élaborés lors de l'exécution.

Richard
la source
3

Ceci est une belle vidéo youtube qui parle de varVS Dynamicavec une démonstration pratique.

Voici une explication plus détaillée avec un instantané.

Var est lié tôt (vérifié statiquement) tandis que dynamique est lié tardivement (évalué dynamiquement).

Le mot-clé var examine vos données de droite, puis pendant la compilation, il décide du type de données de gauche. En d'autres termes, le mot-clé var vous évite de taper beaucoup de choses. Jetez un oeil à l'image ci-dessous où lorsque nous avons donné des données de chaîne et la variable x montre le type de données de chaîne dans mon info-bulle.

entrez la description de l'image ici

D'un autre côté, le mot-clé dynamique a un objectif complètement différent. Les objets dynamiques sont évalués pendant l'exécution. Par exemple, dans le code ci-dessous, la propriété "Length" existe ou non est évaluée pendant l'exécution. J'ai délibérément tapé un petit "l", donc ce programme a compilé très bien mais quand il a été exécuté, il a généré une erreur lorsque la propriété "length" a été appelé (SMALL "l").

entrez la description de l'image ici

Shivprasad Koirala
la source
2

La variable dynamique et la variable var peuvent toutes deux stocker n'importe quel type de valeur, mais il est nécessaire d'initialiser 'var' au moment de la déclaration.

Le compilateur ne possède aucune information sur le type de variable «dynamique». var est sûr pour le compilateur, c'est-à-dire que le compilateur a toutes les informations sur la valeur stockée, de sorte qu'il ne cause aucun problème au moment de l'exécution.

Le type dynamique peut être passé comme argument de fonction et la fonction peut également le renvoyer. Le type de var ne peut pas être passé comme argument de fonction et la fonction ne peut pas retourner le type d'objet. Ce type de variable peut fonctionner dans la portée où il a été défini.

En cas de Casting dynamique n'est pas nécessaire, mais vous devez connaître la propriété et les méthodes liées au type stocké, tandis que pour var Pas besoin de cast car le compilateur a toutes les informations pour effectuer l'opération.

dynamic: utile lors du codage à l'aide de la réflexion ou de la prise en charge d'un langage dynamique ou avec les objets COM, car nous avons besoin d'écrire moins de code.

var: utile pour obtenir le résultat des requêtes linq. Dans le framework 3.5, il présente la prise en charge de la fonction linq.

Référence: Counsellingbyabhi

Abhishek Gahlout
la source
2
  1. Var et dynamique définissent le type.
  2. var au moment de la compilation tandis que dynamic est au moment de l'exécution.
  3. dans la déclaration var et l'initialisation sont obligatoires comme variable constante tout en
  4. dans l'initialisation dynamique peut être au moment de l'exécution comme des variables en lecture seule.
  5. en type var quel que soit le type sont décidés au moment de l'initialisation ne peut pas changer ensuite, mais
  6. dynamique peut également adopter n'importe quel type, même le type de données défini par l'utilisateur.
shhhhh
la source
1

Ne confondez pas dynamique et var. La déclaration d'une variable locale à l'aide de var n'est qu'un raccourci syntaxique permettant au compilateur de déduire le type de données spécifique d'une expression. Le mot clé var ne peut être utilisé que pour déclarer des variables locales dans une méthode tandis que le mot clé dynamique peut être utilisé pour des variables, des champs et des arguments locaux. Vous ne pouvez pas convertir une expression en var, mais vous pouvez convertir une expression en dynamique. Vous devez initialiser explicitement une variable déclarée à l'aide de var alors que vous n'avez pas à initialiser une variable déclarée avec dynamic.

Kartik M
la source
1
  1. Le mot-clé Var (implicit typed local variable) est utilisé pour définir les variables locales. Dans le cas de Var, le type de données sous-jacent est déterminé au moment de la compilation lui-même en fonction de l'affectation initiale.Une fois que l'affectation initiale a été effectuée avec le type Var, alors il deviendra fortement typé. Si vous essayez de stocker une valeur incompatible avec le type Var, cela entraînera une erreur de temps de compilation.

Exemple:

Var strNameList=new List<string>(); By using this statement we can store list of names in the string format. 
strNameList.add("Senthil");
strNameList.add("Vignesh");

strNameList.add(45); // This statement will cause the compile time error.

Mais dans le type dynamique, le type sous-jacent est déterminé uniquement au moment de l'exécution.Le type de données dynamique n'est pas vérifié au moment de la compilation et il n'est pas non plus fortement typé.Nous pouvons attribuer n'importe quelle valeur initiale pour le type dynamique, puis il peut être réaffecté à tout nouveau valeur pendant sa durée de vie.

Exemple:

dynamic test="Senthil";
Console.Writeline(test.GetType())  // System.String

test=1222;
Console.Writeline(test.GetType())  // System.Int32

test=new List<string>();
Console.Writeline(test.GetType())  //System.Collections.Generic.List'1[System.String]

Il ne fournit pas non plus de support IntelliSense, il ne fournit pas un meilleur support lorsque nous donnons également du travail avec linq, car il ne prend pas en charge les expressions lambda, les méthodes d'extension et les méthodes anonymes.

kuttychutty
la source
1

Voici les différences

  • var est typé statiquement (au moment de la compilation), dynamic est typé dynamiquement (au moment de l'exécution)

  • Une variable déclarée comme var ne peut être utilisée que localement, des variables dynamiques peuvent être passées en tant que paramètres pour fonctionner (la signature de fonction peut définir un paramètre comme dynamique mais pas var).

  • avec dynamic, la résolution des propriétés se produit au moment de l'exécution et ce n'est pas le cas avec var, ce qui signifie qu'au moment de la compilation, toute variable déclarée comme dynamique peut appeler une méthode qui peut ou non exister et donc le compilateur ne générera pas d'erreur.

  • Le cast de type avec var n'est pas possible mais avec dynamique c'est possible (vous pouvez cast un objet comme dynamique mais pas comme var).

Arun Vijayraghavan

Arun Vijayraghavan
la source