动态(C#4)和var和有什么区别?


199

我已经阅读了很多有关C#v4附带的新关键字的文章,但是我看不出“ dynamic”和“ var”之间的区别。

这篇文章让我考虑了一下,但是我仍然看不到任何区别。

您是否只能将“ var”用作局部变量,但可以同时用作局部变量和全局变量?

您能显示一些没有动态关键字的代码,然后再显示具有动态关键字的相同代码吗?

Answers:


455

var是静态类型的-编译器和运行时知道类型-它们只是为您节省了一些键入内容...以下内容是100%相同的:

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

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

发生的所有事情是编译器发现它s必须是一个字符串(来自初始化程序)。在这两种情况下,它都知道(在IL中)s.Length意味着(实例)string.Length属性。

dynamic完全不同的野兽;它与最为相似object,但是具有动态分配功能:

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

在这里,s键入为dynamic。它不知道string.Length,因为它不知道任何有关s在编译时。例如,以下代码也将编译(但不运行):

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

在运行时(仅),它将检查FlibbleBananaSnowball属性-找不到它,并在火花中爆炸。

使用dynamic,可以在运行时根据实际对象解析属性/方法/运算符/等。与COM(可以具有仅运行时属性),DLR或其他动态系统(例如)交谈非常方便javascript


3
一个有趣的问题是,是否存在静态声明的类的动态祖先。示例:类X {public int Y {get; set;}} dynamic(X)s = GetSpecialX(); 调用字符串test = sY; 会产生编译器错误,因为编译器知道Y,但是字符串test2 = sZ可以正常编译并在运行时进行检查。我可以想到这种半动态类的很多价值!
mmmmmmmm 2009年

@rstevens-IIRC,您可以通过接口添加动态行为(尽管不存在直接语言支持在C#中实现动态类型-仅使用它们),所以这并非不现实...哦,我们可能会很开心;- p
Marc Gravell

尽管必须指出,有时var可能会推断出由于子类型和隐式强制转换而可能不需要的类型,但这很重要。也就是说,var可能在隐式强制转换发生时解决了与预期静态不同的类型(最明显的是更通用的类型,但不限于此)。一个简单的例子是object x = ""vs. var x = ""vs. var x = "" as object,但是其他更狡猾(更现实)的情况也可能发生,并且可能导致细微的错误。

为了进一步阐述Marc的好例子,在第一种情况下(具有静态类型),编译器确切地知道要调用的许多重载中的WriteLine哪一个。这种“绑定”发生在编译时。在with的情况下dynamic,的类型.Length也必须是dynamic,并且直到运行时才确定哪个重载(如果有的话)WriteLine最合适。绑定在运行时发生。
杰普·斯蒂格·尼尔森

4
当您将鼠标悬停var在Visual Studio中时,将显示正在推断的实际类型。向您显示该类型在编译时是已知的。
克里斯蒂安·弗雷德

56

var声明的变量是隐式但静态类型的。用dynamic声明的变量是动态类型的。此功能已添加到CLR,以支持诸如Ruby和Python之类的动态语言。

我应该补充一点,这意味着动态声明在运行时解析,而var声明在编译时解析。


42

我将解释dynamicvar之间的区别。

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

这将起作用。编译器可以重新创建动态变量的类型。
首先,它将类型创建为整数,然后该编译器将重新创建类型为字符串,
但是对于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 


使用' var '关键字时,类型由编译器在编译时确定,而使用' dynamic '关键字时,类型由运行时确定。
' var '关键字,一个强隐式类型化的局部变量,编译器可以通过该变量来从初始化表达式确定类型-在进行LINQ编程时非常有用。
编译器没有有关变量动态类型的任何信息。因此编译器将不会显示任何智能。
编译器具有有关var 类型存储值的所有信息,因此编译器将显示智能。
动态类型可以作为函数参数传递,函数也可以返回对象类型,
但是
var类型不能作为函数参数传递,并且函数不能返回对象类型。这种类型的变量可以在其定义的范围内工作。


14

var表示已应用静态类型检查(早期绑定)。dynamic表示应用了动态类型检查(后期绑定)。就代码而言,请考虑以下内容:

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

如果您对此进行编译并使用ILSpy检查结果,则会发现编译器添加了一些后期绑定代码,该代码将处理从b调用Hello()的过程,而由于将早期绑定应用于a,a能够调用Hello ()直接。

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

发现差异的最好办法是编写一个像这样的小型控制台应用程序,并使用ILSpy对其进行测试。


关于IL在编译后如何对待它们的一个基本例子。谢谢。
国王

12

一大不同-您可以拥有动态返回类型。

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}

10

这是一个简单的示例,展示了Dynamic(4.0)和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.

湿婆玛米迪


2
我的印象是,**代码示例中字符的存在仅用于表示重点,而不是真正的工作代码的一部分。
DavidRR

7

var 只是普通类型声明的简写,您可以让编译器猜测正确的类型。

dynamic 是一种新的(静态)类型,其中所有检查均在运行时完成,而不是由编译器完成。


4

用var声明的变量的类型由编译器确定,这是指定类型名称的捷径,仅此而已。

但是,动态性是在运行时确定的,编译器不知道实际类型,并且使用该变量进行的所有方法/字段/属性访问都将在运行时进行计算。


3

是一个不错的youtube视频,其中通过实际演示谈论了varVS。Dynamic

以下是快照的详细说明。

Var早期绑定(静态检查),而dynamic后期绑定(动态评估)。

var关键字查看您的右侧数据,然后在编译时决定左侧数据的类型。换句话说,var关键字可以节省您键入许多内容。看下面的图片,当我们给定字符串数据并且x变量在我的工具提示中显示字符串数据类型时。

在此处输入图片说明

另一方面,dynamic关键字用于完全不同的目的。动态对象在运行时进行评估。例如,在下面的代码中,运行时会评估“ Length”属性是否存在。我特意键入了一个小“ l”,因此该程序编译良好,但是当其实际执行时,当“ length”属性出现错误被称为(小“ l”)。

在此处输入图片说明


2

动态变量和var变量都可以存储任何类型的值,但在声明时需要初始化'var'。

编译器没有有关变量“动态”类型的任何信息。var是编译器安全的,即编译器具有关于存储值的所有信息,因此在运行时不会引起任何问题。

动态类型可以作为函数参数传递,函数也可以返回它。变量类型不能作为函数参数传递,函数不能返回对象类型。这种类型的变量可以在其定义的范围内工作。

在不需要动态转换的情况下,但您需要了解与存储类型有关的属性和方法,而对于var则不需要转换,因为编译器具有执行操作的所有信息。

动态的:当使用反射或动态语言支持或使用COM对象进行编码时很有用,因为我们需要编写更少的代码。

var:从linq查询中获取结果时很有用。它在3.5框架中介绍了支持linq功能。

参考:Counsellingbyabhi


2
  1. Var和动态定义类型。
  2. var在编译时,而dynamic在运行时。
  3. 在var声明和初始化中都是强制性的,就像常量变量一样,而
  4. 动态初始化可以像只读变量一样在运行时进行。
  5. 在var类型中,初始化时决定的任何类型都不能更改,但是
  6. 动态的也可以采用任何类型,甚至用户也可以定义数据类型。

1

不要混淆dynamic和var。使用var声明局部变量只是语法上的捷径,它使编译器从表达式中推断出特定的数据类型。var关键字只能用于在方法内部声明局部变量,而dynamic关键字可以用于局部变量,字段和参数。您不能将表达式转换为var,但是可以将表达式转换为动态。您不必显式初始化使用var声明的变量,而不必初始化使用dynamic声明的变量。


1
  1. Var(隐式类型局部变量)关键字用于定义局部变量。对于Var而言,底层数据类型是在编译时根据初始赋值确定的。一旦使用Var类型进行了初始赋值,则它如果您尝试使用Var类型存储任何不兼容的值,则会导致编译时错误。

例:

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.

但是在动态类型中,基础类型仅在运行时确定。动态数据类型在编译时不检查,也不是强类型的。我们可以为动态类型分配任何初始值,然后可以将其重新分配给任何新值一生中的价值。

例:

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]

它也没有提供IntelliSense支持。当我们也使用linq时,它也没有提供更好的支持。因为它不支持lambda表达式,扩展方法和匿名方法。


1

这是差异

  • var是静态类型的(编译时),dynamic是动态类型的(运行时)

  • 声明为var的变量只能在本地使用,动态变量可以作为参数传递给函数(函数签名可以将参数定义为dynamic而不是var)。

  • 如果使用动态,则属性解析将在运行时发生,而使用var则不是这样,这意味着在编译时,任何声明为动态的变量都可以调用可能存在或不存在的方法,因此编译器不会引发错误。

  • 使用var进行类型转换是不可能的,但使用动态转换是可能的(可以将对象转换为动态而不是var)。

阿伦(Arun Vijayraghavan)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.