¿Cuál es la diferencia entre dinámico (C # 4) y var?


199

Había leído un montón de artículos sobre esa nueva palabra clave que se envía con C # v4, pero no pude distinguir la diferencia entre una "dinámica" y "var".

Este artículo me hizo pensar en ello, pero todavía no veo ninguna diferencia.

¿Puede usar "var" solo como una variable local, pero dinámico como local y global?

¿Podría mostrar algún código sin palabra clave dinámica y luego mostrar el mismo código con palabra clave dinámica?

Respuestas:


455

vares de tipo estático - el compilador y el tiempo de ejecución conocen el tipo - solo le ahorran algo de tipeo ... los siguientes son 100% idénticos:

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

y

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

Todo lo que sucedió fue que el compilador descubrió que sdebe ser una cadena (del inicializador). En ambos casos, sabe (en la IL) que s.Lengthsignifica la string.Lengthpropiedad (instancia) .

dynamices una bestia muy diferente; es más similar a object, pero con despacho dinámico:

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

Aquí, sse escribe como dinámico . Que no sabe nada string.Length, ya que no sabe nada acerca de sen tiempo de compilación. Por ejemplo, lo siguiente también se compilaría (pero no se ejecutaría):

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

En tiempo de ejecución (solo), verificaría la FlibbleBananaSnowballpropiedad, no la encontraría y explotaría en una lluvia de chispas.

Con dynamicpropiedades, métodos / operadores / etc. se resuelven en tiempo de ejecución , en función del objeto real. Muy útil para hablar con COM (que puede tener propiedades de tiempo de ejecución solamente), el DLR u otros sistemas dinámicos, como javascript.


3
Una pregunta interesante sería si hay antepasados ​​dinámicos de clases declaradas estáticamente. Ejemplo: clase X {public int Y {get; set;}} dynamic (X) s = GetSpecialX (); Llamar a prueba de cadena = sY; generaría un error del compilador porque el compilador conoce Y, pero string test2 = sZ se compilaría bien y se verificaría en tiempo de ejecución. ¡Podría pensar en mucho valor de tales clases semidinámicas!
mmmmmmmm

@rstevens - IIRC, puede agregar un comportamiento dinámico a través de una interfaz (aunque no hay soporte directo de lenguaje para implementar tipos dinámicos en C #, solo consumirlos), por lo que esto no es poco realista ... oh, la diversión que podríamos tener; p
Marc Gravell

Aunque es importante tener en cuenta que a veces se varpueden inferir tipos que podrían no ser deseables debido a subtipos y conversiones implícitas. Es decir, varpuede haber resuelto un tipo estáticamente diferente de lo esperado cuando ocurren conversiones implícitas (más notablemente a un tipo más general, pero no se limita a esto). Un ejemplo trivial es object x = ""vs var x = ""vs. var x = "" as object, pero pueden ocurrir otros casos más astutos (y realistas) y pueden causar errores sutiles.

Para dar más detalles sobre el buen ejemplo de Marc, en el primer caso (con tipo estático), el compilador sabe exactamente a cuál de las muchas sobrecargas seWriteLine debe llamar. Este "enlace" ocurre en tiempo de compilación. En el caso de dynamic, el tipo de .Lengthtiene que ser dynamictambién, y no es hasta el tiempo de ejecución que se decide qué sobrecarga (si es que la hay) se WriteLineajusta mejor. El enlace ocurre en tiempo de ejecución.
Jeppe Stig Nielsen

44
Cuando coloca el cursor sobre la varpalabra clave en Visual Studio, se muestra el tipo real que se infiere. Le muestra que el tipo es conocido en tiempo de compilación.
Christian Fredh

56

Las variables declaradas con var se tipean implícita pero estáticamente . Las variables declaradas con dinámico se escriben dinámicamente. Esta capacidad se agregó al CLR para admitir lenguajes dinámicos como Ruby y Python.

Debo agregar que esto significa que las declaraciones dinámicas se resuelven en tiempo de ejecución, las declaraciones var se resuelven en tiempo de compilación.


42

Voy a explicar la diferencia entre dinámica y var .

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

Esto funcionará El compilador puede recrear el tipo de variable dinámica .
primero crea el tipo como entero y luego ese compilador recreará el tipo como cadena
pero en 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 


Cuando se usa la palabra clave ' var ', el compilador decide el tipo en el momento de la compilación, mientras que cuando se usa la palabra clave ' dinámica ', el tiempo de ejecución decide el tipo.
Palabra clave ' var ', una variable local fuertemente tipada implícitamente para la cual el compilador puede determinar el tipo a partir de la expresión de inicialización, muy útil cuando se realiza la programación LINQ.
El compilador no tiene ninguna información sobre el tipo dinámico de variable. entonces el compilador no mostrará ninguna inteligencia.
El compilador tiene toda la información sobre el valor almacenado del tipo var, por lo que el compilador mostrará inteligencia.
el tipo dinámico se puede pasar como argumento de función y la función también puede devolver el tipo de objeto
Pero el tipo
var no se puede pasar como argumento de función y la función no puede devolver el tipo de objeto. Este tipo de variable puede funcionar en el ámbito donde se definió.


14

var implica que se aplica la comprobación de tipo estático (enlace temprano). dinámico implica que se aplica la verificación de tipo dinámico (enlace tardío). En términos del código, tenga en cuenta lo siguiente:

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 compila esto e inspecciona los resultados con ILSpy, encontrará que el compilador ha agregado un código de enlace tardío que manejará la llamada a Hello () desde b, mientras que el enlace temprano se aplicó a a, a puede llamar a Hello () directamente.

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

Lo mejor que puede hacer para descubrir la diferencia es escribirse una pequeña aplicación de consola como esta y probarla usted mismo con ILSpy.


Un gran ejemplo básico sobre cómo IL los trata a ambos después de la compilación. Gracias.
Reyes

12

Una gran diferencia: puede tener un tipo de retorno dinámico.

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}

10

Aquí hay un ejemplo simple que demuestra la diferencia entre Dynamic (4.0) y 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


2
Mi impresión es que la presencia de **caracteres en el ejemplo de código tiene la intención de indicar solo énfasis y no pretende ser parte del código de trabajo real.
DavidRR

7

var es solo una abreviatura de una declaración de tipo normal, donde permite que el compilador adivine el tipo correcto.

dynamic es un nuevo tipo (estático), donde todas las comprobaciones se realizan en tiempo de ejecución, no por el compilador.


4

El compilador determina el tipo de una variable declarada con var, es un atajo para especificar el nombre del tipo, nada más.

Sin embargo, la dinámica se determina en tiempo de ejecución, el compilador no tiene idea del tipo real y todos los accesos de método / campo / propiedad con esa variable se resolverán en tiempo de ejecución.


3

Este es un buen video de YouTube que habla sobre varVS Dynamiccon una demostración práctica.

A continuación se muestra una explicación más detallada con una instantánea.

Var está enlazado antes (estáticamente verificado) mientras que dinámico está enlazado tarde (evaluado dinámicamente).

La palabra clave Var analiza los datos de su lado derecho y luego, durante el tiempo de compilación, decide el tipo de datos de la izquierda. En otras palabras, la palabra clave var simplemente le ahorra escribir muchas cosas. Eche un vistazo a la imagen a continuación, donde cuando hemos dado datos de cadena y la variable x muestra el tipo de datos de cadena en mi información sobre herramientas.

ingrese la descripción de la imagen aquí

Por otro lado, la palabra clave dinámica tiene un propósito completamente diferente. Los objetos dinámicos se evalúan durante el tiempo de ejecución. Por ejemplo, en el código siguiente, la propiedad "Longitud" existe o no se evalúa durante el tiempo de ejecución. He escrito una pequeña "l" a propósito, por lo que este programa se compiló bien, pero cuando realmente se ejecutó arrojó un error cuando la propiedad "longitud" fue llamado (PEQUEÑO "l").

ingrese la descripción de la imagen aquí


2

La variable dinámica y la variable var pueden almacenar cualquier tipo de valor, pero es necesario para inicializar 'var' en el momento de la declaración.

El compilador no tiene ninguna información sobre el tipo de variable "dinámica". var es seguro para el compilador, es decir, el compilador tiene toda la información sobre el valor almacenado, por lo que no causa ningún problema en tiempo de ejecución.

El tipo dinámico se puede pasar como argumento de función y la función también puede devolverlo. El tipo Var no se puede pasar como argumento de función y la función no puede devolver el tipo de objeto. Este tipo de variable puede funcionar en el ámbito donde se definió.

En el caso de la conversión dinámica no es necesaria, pero debe conocer la propiedad y los métodos relacionados con el tipo almacenado, mientras que para var no es necesario emitir porque el compilador tiene toda la información para realizar la operación.

dinámico: útil cuando se codifica utilizando la reflexión o el soporte de lenguaje dinámico o con los objetos COM, porque necesitamos escribir menos cantidad de código.

var: útil cuando se obtienen resultados de las consultas linq. En el marco 3.5 se presenta para admitir la función linq.

Referencia: Counsellingbyabhi


2
  1. Var y dinámica definen el tipo.
  2. var en el tiempo de compilación mientras que el dinámico está en tiempo de ejecución
  3. en la declaración e inicialización var, ambos son obligatorios como variable constante mientras
  4. en la inicialización dinámica puede ser en tiempo de ejecución como variables de solo lectura.
  5. en el tipo var, cualquier tipo que se decida en el momento en que la inicialización no puede cambiar a continuación, pero
  6. Dynamic puede adoptar cualquier tipo incluso el usuario define el tipo de datos también.

1

No confundir dinámico y var. Declarar una variable local usando var es solo un atajo sintáctico que hace que el compilador infiera el tipo de datos específico de una expresión. La palabra clave var solo se puede usar para declarar variables locales dentro de un método, mientras que la palabra clave dinámica se puede usar para variables locales, campos y argumentos. No puede convertir una expresión en var, pero puede convertir una expresión en dinámica. Debe inicializar explícitamente una variable declarada usando var, mientras que no tiene que inicializar una variable declarada con dinámica.


1
  1. La palabra clave Var (variable local de tipo implícito) se utiliza para definir variables locales. En el caso de Var, el tipo de datos subyacente se determina en el momento de la compilación en función de la asignación inicial. Una vez que la asignación inicial se ha realizado con el tipo Var, entonces será fuertemente tipado. Si intenta almacenar cualquier valor incompatible con el tipo Var, se producirá un error de tiempo de compilación.

Ejemplo:

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.

Pero en el tipo dinámico, el tipo subyacente se determina solo en el tiempo de ejecución. El tipo de datos dinámico no se verifica en el momento de la compilación y tampoco está fuertemente tipado. Podemos asignar cualquier valor inicial para el tipo dinámico y luego se puede reasignar a cualquier nuevo valor durante su vida útil.

Ejemplo:

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]

Tampoco proporciona soporte IntelliSense. No brinda un mejor soporte cuando damos trabajo con linq también. Porque no admite expresiones lambda, métodos de extensión y métodos anónimos.


1

Aquí están las diferencias.

  • var se escribe estáticamente (tiempo de compilación), dinámico se escribe dinámicamente (tiempo de ejecución)

  • Una variable declarada como var solo puede usarse localmente, las variables dinámicas pueden pasarse como parámetros para funcionar (la firma de función puede definir un parámetro como dinámico pero no var).

  • con dinámico, la resolución de las propiedades ocurre en tiempo de ejecución y ese no es el caso con var, lo que significa que en tiempo de compilación cualquier variable declarada como dinámica puede llamar a un método que puede existir o no, por lo que el compilador no arrojará un error.

  • La conversión de tipos con var no es posible pero con dinámica es posible (puede convertir un objeto como dinámico pero no como var).

Arun Vijayraghavan

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.