ChatGPT解决这个技术问题 Extra ChatGPT

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

我已经阅读了大量关于 C# v4 附带的新关键字的文章,但我无法区分“动态”和“var”之间的区别。

This article 让我思考了一下,但我仍然看不出有什么不同。

是不是您只能将“var”用作局部变量,而将其用作局部变量和全局变量?

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


M
Marc Gravell

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 被键入动态。它不知道 string.Length,因为它在编译时不知道 s任何事情。例如,以下代码也可以编译(但不能运行):

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

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

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


一个有趣的问题是静态声明的类是否存在动态祖先。示例:class X { public int Y {get;set;} } dynamic(X) s = GetSpecialX();调用字符串 test = sY;会产生编译器错误,因为编译器知道 Y 但 string test2 = sZ 会编译得很好并在运行时进行检查。我可以想到这种半动态类的价值!
@rstevens - IIRC,您可以通过接口添加动态行为(尽管没有直接的语言支持在 C# 中实现动态类型 - 仅使用它们),所以这并非不切实际......哦,我们可以有乐趣;- p
尽管需要注意的是,有时 var 可以推断出由于子类型和隐式转换而可能不需要的类型。也就是说,当发生 implicit 强制转换时,var 可能已解析出与预期不同的静态类型(最明显的是更通用的类型,但不限于此)。一个简单的例子是 object x = "" vs. var x = "" vs. var x = "" as object,但可能会发生其他更偷偷摸摸(和现实)的情况,并可能导致细微的错误。
为了进一步详细说明 Marc 的好示例,在第一种情况下(使用静态类型),编译器确切地知道要调用哪个 many overloads of WriteLine。这种“绑定”发生在编译时。在 dynamic 的情况下,.Length 的类型也必须是 dynamic,直到运行时才决定 WriteLine 的哪个重载(如果有的话)最适合。绑定发生在运行时。
在 Visual Studio 中悬停 var 关键字时,会显示正在推断的实际类型。向您显示该类型在编译时是已知的。
H
Hans Van Slooten

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

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


D
Darrel Hoffman

我将解释动态和var之间的区别。

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类型不能作为函数参数传递,函数不能返回对象类型。这种类型的变量可以在它定义的范围内工作。


M
Matthew Layton

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 在编译后如何处理它们的很好的基本示例。谢谢。
u
user2382351

一个很大的区别 - 你可以有一个动态的返回类型。

dynamic Foo(int x)
{
    dynamic result;

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

    return result;
}

C
CoolBeans

这是一个简单的例子,它演示了 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.

湿婆玛米迪


我的印象是,代码示例中存在 ** 字符只是为了表示重点,而不是作为实际工作代码的一部分。
g
gimel

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

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


R
Richard

用 var 声明的变量的类型由编译器决定,它是指定类型名称的快捷方式,仅此而已。

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


S
Shivprasad Koirala

This is a nice youtube video 通过实际演示讨论 var VS Dynamic

以下是快照的更详细说明。

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

var 关键字查看您的右手边数据,然后在编译时决定左手边的数据类型。换句话说,var 关键字只是节省您输入很多东西。看看下图,当我们给定字符串数据并且 x 变量在我的工具提示中显示字符串数据类型时。

https://i.stack.imgur.com/qByqr.png

另一方面,动态关键字用于完全不同的目的。动态对象在运行时进行评估。例如,在下面的代码中,“长度”属性是否存在是在运行时评估的。我特意输入了一个小的“l”,所以这个程序编译得很好,但是当它实际执行时,它在“长度”属性时抛出了一个错误被称为(小“l”)。

https://i.stack.imgur.com/FkuCw.png


A
Arun Vijayraghavan

以下是区别

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

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

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

无法使用 var 进行类型转换,但可以使用动态类型转换(您可以将对象转换为动态但不能转换为 var)。

阿伦·维杰拉哈万


A
Abhishek Gahlout

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

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

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

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

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

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

参考:Counsellingbyabhi


s
shhhhh

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


K
Kartik M

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


A
Andrew Barber

Var(Implicit typed local variable) 关键字用于定义局部变量。在 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 表达式、扩展方法和匿名方法。