匿名类型与动态类型

时间:2008-12-24 14:28:20

标签: c# .net dynamic anonymous-types

c#3.0中的匿名类型(var)和c#4.0中的动态类型(动态)之间有什么真正的区别?

6 个答案:

答案 0 :(得分:90)

你似乎在混合三种完全不同的正交事物:

  • 静态与动态输入
  • 清单与隐式输入
  • 命名与匿名类型

这三个方面是完全独立的,彼此没有任何关系。

静态与动态类型是指何时进行类型检查:动态类型在运行时进行,静态类型发生< em>在运行时之前。

清单与隐式类型是指类型是否在源代码中清单:清单类型意味着程序员具有将类型写入源代码中,隐式类型意味着类型系统自行计算出来。

命名与匿名类型是指类型是否具有名称。

C#4.0中的dynamic关键字表示此变量,参数,方法,字段,属性...... 动态类型,即其类型将在运行时检查。未输入动态的所有内容都是静态类型的。类型是静态还是动态不仅决定何时进行类型检查,而且在C#4.0中它还确定何时发生方法分派。在C#中,方法调度在运行时之前完成,基于静态类型(当然,运行时子类型多态性除外),而在C#4.0中的动态类型对象上,方法调度在运行时根据运行时类型完成。 / p>

C#3.0中的var关键字意味着此局部变量将隐式输入,即代替程序员明确写下该类型,类型系统将在它自己的。这与动态类型无关,至少在C#3.0中是这样。该变量将被强烈静态输入,就像您自己写下该类型一样。这只是一个方便:例如,当类型系统明确弄明白时,为什么你必须在HashMap<int, string> foo = new HashMap<int, string>();中写下所有类型名称​​两次 fooHashMap<int, string>,因此请您编写var foo = new HashMap<int, string();。请注意,这没有任何动态或匿名。类型是静态的,它的名称为:HashMap<int, string>。当然,在C#4.0中,如果类型系统指出赋值的右侧是动态的,那么左侧变量的类型将是动态的。

C#3.0中的匿名类型表示此类型没有名称。那么,实际上,真正的匿名类型需要对Common Type System进行向后不兼容的更改,因此幕后发生的实际是编译器将生成一个非常该类型的长,非常随机,唯一和非法的名称,并将该名称放在匿名类型出现的位置。但从程序员的角度来看,该类型没有名称。为什么这有用?好吧,有时你会得到中间结果,你只需要简单然后再扔掉。给这些瞬态类型一个自己的名称会将它们提升到他们根本不应该得到的重要程度。但同样,这没有任何动态。

因此,如果类型没有名称,程序员如何引用它?好吧,她不能!至少不是直接的。程序员可以做什么,是描述类型:它有两个属性,一个叫做string类型的“名称”,另一个叫int类型的“id”。这就是我想要的类型,但我不在乎它叫什么。

这是作品开始融合的地方。在C#中,您必须通过显式写下类型的名称来声明局部变量的类型。但是,你怎么能写下一个没有名字的类型的名字呢?这就是var的用武之地:因为自C#3.0以来,这实际上已经不再适用了:你不再需要记下这些名字,你也可以告诉编译器弄清楚它。因此,虽然我在上面第一段中所写的内容是真的,但隐式类型和匿名类型与其他类型没有任何关系,如果没有隐式类型,匿名类型也会毫无用处。

但请注意,情况恰恰相反:如果没有匿名类型,隐式类型非常有用。 var foo = HashMap<int, string>非常有意义,并且看不到匿名类型。

答案 1 :(得分:19)

匿名类型是为您创建的真实的编译器生成类型。关于这一点的好处是编译器可以稍后重新使用此类型用于需要它的其他操作,因为它是POCO。

我对动态类型的理解是它们是后期绑定的,这意味着CLR(或DLR)将在执行时评估对象,然后使用duck typing来允许或禁止成员访问该对象。

所以我猜不同的是,匿名类型是编译器可以看到的真正的POCO,但是你只能使用动态类型是后期绑定的动态对象。

答案 2 :(得分:18)

dynamic类型本质上是object,但会通过DLR或其他提供程序(例如反射)解析运行时的所有方法/属性/运算符等调用

这使得它与带有Option Strict Off的VB非常相似,并且使其在调用COM或DLR类型时非常通用。

在编译时使用动态进行 no 类型检查;顺便提一下,匿名类型是适当的静态类型,类型检查的野兽(你可以在反射器中看到它们,虽然它们不漂亮)。

此外,匿名类型可以由编译器专门处理; dynamic需要大量的运行时支持 - 所以匿名类型是C#特性,但dynamic将主要由.NET 4.0实现(支持一些C#4.0)。

答案 3 :(得分:8)

在这里查看Ander的演示文稿:

http://channel9.msdn.com/pdc2008/TL16/

HTM

答案 4 :(得分:6)

有三次,有三个演员 - 每次一个。

  • 设计时 - 程序员
  • 编译时 - c#编译器
  • 运行时 - .net运行时

匿名类型由编译器声明和命名。该声明基于程序员的规范(他如何使用该类型)。由于这些类型是以程序员离开过程命名的,因此它们似乎对程序员来说是无名的,因此是“匿名的”。

  • 程序员说:某些类型有名称和地址
  • 编译器说:有一个名为xyz的类型,其中包含名称和地址属性以及字段,两个字符串。
  • 运行时说:我无法区分xyz和程序员所做的任何类型。

c#中的动态类型允许您调用在编译时可能存在或不存在的方法。这对于调用未编译的python或javascript非常有用。

  • 程序员说:将这个汽车实例视为动态类型。现在,嘎嘎。
  • 编译器说:动态打字呃?一定没事。我不会抱怨,因为我无法检查。
  • 运行时尝试制作car的实例,嘎嘎。

答案 5 :(得分:1)

没有什么比清除一些代码更简单了:

// anonymous types
var anonType = new {Id = "123123123", Name = "Goku", Age = 30, DateAdded = new DateTime()};
// notice we have a strongly typed anonymous class we can access the properties with
Console.WriteLine($"Anonymous Type: {anonType.Id} {anonType.Name} {anonType.Age} {anonType.DateAdded}");
// compile time error
//anonType = 100;

// dynamic types
dynamic dynType = 100.01m;
Console.WriteLine($"Dynamic type: {dynType}");
// it's ok to change the type however you want
dynType = new List<DateTime>();
Console.WriteLine($"Dynamic type: {dynType}");

// mix dynamic and anonymous
dynamic dynamicAnonymousType = new {Id = 8000, FirstName = "Goku", Gender = "male", IsSuperSaiyan = true};
// Wasn't sure this would work but it does! However, you lose intellisense on the FirstName so you have to type it manually.
Console.WriteLine($"FirstName: {dynamicAnonymousType.FirstName}");
dynamicAnonymousType = 100;
Console.WriteLine(dynamicAnonymousType);
// runtime error
Console.WriteLine($"Id: {dynamicAnonymousType.FirstName}");