Qual é a diferença entre dinâmico (C # 4) e var?

199

Eu tinha lido vários artigos sobre essa nova palavra-chave que é fornecida com o C # v4, mas não consegui distinguir a diferença entre "dinâmico" e "var".

Este artigo me fez pensar sobre isso, mas ainda não vejo diferença.

Você pode usar "var" apenas como uma variável local, mas dinâmico como local e global?

Você poderia mostrar algum código sem a palavra-chave dinâmica e depois mostrar o mesmo código com a palavra-chave dinâmica?

Ivan Prodanov
fonte

Respostas:

455

varé digitado estático - o compilador e o tempo de execução sabem o tipo - eles apenas economizam sua digitação ... os seguintes são 100% idênticos:

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

e

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

Tudo o que aconteceu foi que o compilador descobriu que sdeve ser uma string (do inicializador). Nos dois casos, ele sabe (no IL) que s.Lengthsignifica a string.Lengthpropriedade (instance) .

dynamicé um animal muito diferente; é mais parecido com object, mas com despacho dinâmico:

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

Aqui, sé digitado como dinâmico . Ele não sabe sobre string.Length, porque ele não sabe nada sobre sem tempo de compilação. Por exemplo, o seguinte também seria compilado (mas não executado):

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

Em tempo de execução (apenas), ele verifica a FlibbleBananaSnowballpropriedade - falha em encontrá-la e explode em uma chuva de faíscas.

Com dynamic, propriedades / métodos / operadores / etc são resolvidos em tempo de execução , com base no objeto real. Muito útil para conversar com o COM (que pode ter propriedades apenas de tempo de execução), o DLR ou outros sistemas dinâmicos, como javascript.

Marc Gravell
fonte
3
Uma pergunta interessante seria se existem ancestrais dinâmicos de classes declaradas estaticamente. Exemplo: classe X {public int Y {get; set;}} dynamic (X) s = GetSpecialX (); Chamando string test = sY; geraria um erro do compilador porque o compilador conhece Y, mas a cadeia test2 = sZ seria compilada corretamente e verificada em tempo de execução. Eu poderia pensar em muito valor dessas classes semi-dinâmicas!
mmmmmmmm
@rstevens - IIRC, você pode adicionar comportamento dinâmico por meio de uma interface (embora não exista suporte direto à linguagem para implementar tipos dinâmicos em C # - apenas consumi-los), portanto isso não é irrealista ... ah, a diversão que poderíamos ter; p
Marc Gravell
Embora seja importante observar que, às vezes, é varpossível inferir tipos que podem não ser desejados devido a subtipos e conversões implícitas. Ou seja, varpode ter resolvido um tipo estaticamente diferente do esperado quando ocorrem conversões implícitas (principalmente para um tipo mais geral, mas não se limita a isso). Um exemplo trivial é object x = ""vs. var x = ""vs. var x = "" as object, mas outros casos mais sorrateiros (e realistas) podem ocorrer e podem causar erros sutis.
Para aprofundar o bom exemplo de Marc, no primeiro caso (com tipo estático), o compilador sabe exatamente qual das muitas sobrecargasWriteLine deve chamar. Essa "ligação" acontece em tempo de compilação. No caso de dynamic, o tipo de .Lengthtambém deve ser dynamic, e somente no tempo de execução é decidido qual sobrecarga (se houver alguma) WriteLinese encaixa melhor. A ligação acontece em tempo de execução.
Jeppe Stig Nielsen
4
Quando você passa o mouse pela varpalavra - chave no Visual Studio, o tipo real é exibido que está sendo inferido. Mostra que o tipo é conhecido em tempo de compilação.
Christian Fredh 28/08/2013
56

Variáveis ​​declaradas com var são tipicamente implícitas, mas estaticamente . Variáveis ​​declaradas com dinâmico são digitadas dinamicamente. Esse recurso foi adicionado ao CLR para oferecer suporte a linguagens dinâmicas como Ruby e Python.

Devo acrescentar que isso significa que as declarações dinâmicas são resolvidas em tempo de execução, as declarações var são resolvidas em tempo de compilação.

Hans Van Slooten
fonte
42

Vou explicar a diferença entre dinâmico e var .

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

Isso vai funcionar. O compilador pode recriar o tipo de variável dinâmica .
primeiro, ele cria o tipo como número inteiro e, depois disso, o compilador recriará o tipo como string,
mas no caso 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 


Ao usar a palavra-chave ' var ', o tipo é decidido pelo compilador no momento da compilação, enquanto que ao usar a palavra-chave ' dinâmica ', o tipo é decidido pelo tempo de execução.
A palavra-chave ' var ', uma variável local fortemente tipada implicitamente para a qual o compilador é capaz de determinar o tipo a partir da expressão de inicialização - muito útil ao executar a programação LINQ.
O compilador não possui nenhuma informação sobre o tipo dinâmico de variável. então o compilador não mostrará nenhuma inteligência.
compilador tem todas as informações sobre o valor armazenado de var tipo para que o compilador mostre inteligência.
o tipo dinâmico pode ser passado como argumento de função e a função também pode retornar o tipo de objeto.
Mas o tipo
var não pode ser passado como argumento de função e a função não pode retornar o tipo de objeto. Esse tipo de variável pode funcionar no escopo em que foi definido.

Suneel Gupta
fonte
14

var implica que a verificação de tipo estático (ligação antecipada) é aplicada. dynamic implica que a verificação dinâmica de tipo (ligação tardia) é aplicada. Em termos de código, considere o seguinte:

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

Se você compilar isso e inspecionar os resultados com o ILSpy, descobrirá que o compilador adicionou algum código de ligação tardia que manipulará a chamada para Hello () de b, enquanto que a ligação inicial foi aplicada a a, a poderá chamar Hello () diretamente.

por exemplo (desmontagem do 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);
        }
    }
}

A melhor coisa que você pode fazer para descobrir a diferença é criar um pequeno aplicativo de console como este e testá-lo com o ILSpy.

Matthew Layton
fonte
ótimo exemplo básico de como a IL trata os dois após a compilação. Obrigado.
Reis
12

Uma grande diferença - você pode ter um tipo de retorno dinâmico.

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}
user2382351
fonte
10

Aqui está um exemplo simples que demonstra a diferença entre Dynamic (4.0) e 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
fonte
2
Minha impressão é que a presença de **caracteres no exemplo de código pretende indicar apenas ênfase e não faz parte do código de trabalho real.
DavidRR
7

var é apenas um atalho para uma declaração de tipo normal, na qual você deixa o compilador adivinhar o tipo correto.

dynamic é um novo tipo (estático), em que todas as verificações são feitas em tempo de execução, não pelo compilador.

gimel
fonte
4

O tipo de uma variável declarada com var é determinado pelo compilador, é um atalho para especificar o nome do tipo, nada mais.

Por mais que a dinâmica seja determinada no tempo de execução, o compilador não tem idéia do tipo real e todos os acessos de método / campo / propriedade com essa variável serão trabalhados no tempo de execução.

Richard
fonte
3

Este é um bom vídeo do youtube que fala sobre o varVS Dynamiccom demonstração prática.

Abaixo está uma explicação mais detalhada com o instantâneo.

Var é vinculado antecipadamente (verificado estaticamente) enquanto dinâmico está atrasado (avaliado dinamicamente).

A palavra-chave var analisa seus dados do lado direito e, durante o tempo de compilação, decide o tipo de dados à esquerda. Em outras palavras, a palavra-chave var apenas poupa a digitação de muitas coisas. Dê uma olhada na imagem abaixo, onde, quando fornecemos dados de string e a variável x mostra o tipo de dados de string na minha dica de ferramenta.

insira a descrição da imagem aqui

Por outro lado, a palavra-chave dinâmica é para fins completamente diferentes. Objetos dinâmicos são avaliados durante o tempo de execução. Por exemplo, no código abaixo, a propriedade "Length" existe ou não é avaliada durante o tempo de execução. Digitei propositadamente um pequeno "l"; portanto, esse programa foi compilado corretamente, mas quando foi executado, gerou um erro quando a propriedade "length" foi chamado (SMALL "l").

insira a descrição da imagem aqui

Shivprasad Koirala
fonte
2

A variável dinâmica e a variável var podem armazenar qualquer tipo de valor, mas é necessário inicializar 'var' no momento da declaração.

O compilador não possui nenhuma informação sobre o tipo de variável 'dinâmico'. var é seguro para o compilador, ou seja, o compilador tem todas as informações sobre o valor armazenado, para que não cause nenhum problema no tempo de execução.

O tipo dinâmico pode ser passado como argumento de função e a função também pode retorná-lo. O tipo Var não pode ser passado como argumento de função e a função não pode retornar o tipo de objeto. Esse tipo de variável pode funcionar no escopo em que foi definido.

No caso de transmissão dinâmica, não é necessário, mas você precisa conhecer as propriedades e métodos relacionados ao tipo armazenado, enquanto que para var Não há necessidade de transmissão porque o compilador possui todas as informações para executar a operação.

dynamic: útil ao codificar usando reflexão ou suporte de idioma dinâmico ou com os objetos COM, porque precisamos escrever menos quantidade de código.

var: Útil ao obter resultado das consultas linq. No framework 3.5, ele é apresentado para suportar o recurso linq.

Referência: Counsellingbyabhi

Abhishek Gahlout
fonte
2
  1. Var e tipo de definição dinâmico.
  2. var no tempo de compilação, enquanto dinâmico está no tempo de execução.
  3. na declaração var e inicialização ambos são obrigatórios como variável constante enquanto
  4. na inicialização dinâmica pode ser em tempo de execução como variáveis ​​somente leitura.
  5. no tipo var, qualquer que seja o tipo decidido no momento, a inicialização não pode ser alterada a seguir, mas
  6. O dynamic pode adotar qualquer tipo, mesmo o usuário define o tipo de dados também.
shhhhh
fonte
1

Não confunda dinâmico e var. Declarar uma variável local usando var é apenas um atalho sintático que faz o compilador inferir o tipo de dados específico de uma expressão. A palavra-chave var pode ser usada apenas para declarar variáveis ​​locais dentro de um método, enquanto a palavra-chave dinâmica pode ser usada para variáveis, campos e argumentos locais. Você não pode converter uma expressão em var, mas pode converter uma expressão em dinâmico. Você deve inicializar explicitamente uma variável declarada usando var enquanto não precisar inicializar uma variável declarada com dinâmico.

Kartik M
fonte
1
  1. A palavra-chave Var (variável local digitada implícita) é usada para definir variáveis ​​locais.No caso de Var, o tipo de dados subjacente é determinado no próprio tempo de compilação, com base na atribuição inicial.Uma vez que a atribuição inicial foi feita com o tipo Var, então será fortemente digitado. Se você tentar armazenar qualquer valor incompatível com o tipo Var, isso resultará em erro no tempo de compilação.

Exemplo:

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.

Mas no tipo Dinâmico, o tipo subjacente é determinado apenas no tempo de execução.O tipo de dados dinâmico não é verificado no tempo de compilação e também não é fortemente tipado.Podemos atribuir qualquer valor inicial para o tipo dinâmico e, em seguida, pode ser reatribuído a qualquer novo valor durante sua vida útil.

Exemplo:

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]

Ele não fornece suporte ao IntelliSense e não oferece suporte melhor quando trabalhamos com o linq também, porque não suporta expressões lambda, métodos de extensão e métodos anônimos.

kuttychutty
fonte
1

Aqui estão as diferenças

  • var é digitado estaticamente (tempo de compilação), dinâmico é digitado dinamicamente (tempo de execução)

  • Uma variável declarada como var pode ser usada apenas localmente, variáveis ​​dinâmicas podem ser passadas como parâmetros para a função (a assinatura da função pode definir um parâmetro como dinâmico, mas não var).

  • com dinâmico, a resolução das propriedades acontece no tempo de execução e não é o caso de var, o que significa que, no momento da compilação, qualquer variável declarada como dinâmica pode chamar um método que pode ou não existir e, portanto, o compilador não gera um erro.

  • Digitar conversão com var não é possível, mas dinâmico é possível (você pode converter um objeto como dinâmico, mas não como var).

Arun Vijayraghavan

Arun Vijayraghavan
fonte