匿名类型与动态类型
Posted
技术标签:
【中文标题】匿名类型与动态类型【英文标题】:Anonymous Type vs Dynamic Type 【发布时间】:2010-09-28 08:06:46 【问题描述】:c# 3.0 中的匿名类型(var) 与 c# 4.0 中的动态类型(dynamic) 之间的真正区别是什么?
【问题讨论】:
匿名类型与 var 不同。关键字 var 可以随时被指向,并且在编译时会变成一个真正的类型引用。 var 关键字是语法糖,匿名类型是为您生成的类型。不一样,虽然它们是一起使用的。 匿名类型请查看***.com/questions/17991907/… 【参考方案1】:您似乎在混合三种完全不同的正交事物:
静态与动态类型 清单与隐式键入 命名与匿名类型这三个方面是完全独立的,彼此没有任何关系。
静态与动态类型是指何时进行类型检查:动态类型发生在运行时,静态类型发生运行前。
Manifest vs. implicit类型是指类型是否在源代码中manifest:manifest类型意味着程序员有要将类型写入源代码,隐式类型意味着类型系统自行计算出来。
命名与匿名类型是指类型是否具有名称。
C# 4.0 中的dynamic
关键字表示此变量、参数、方法、字段、属性……无论是动态类型,即将在运行时检查其类型。所有不是动态类型的都是静态类型的。一个类型是静态的还是动态的,不仅决定了何时进行类型检查,而且在 C# 4.0 中,它还决定了何时进行方法调度。在 C# 中,方法分派是在运行时之前完成的,基于静态类型(当然,运行时子类型多态性除外),而在 C# 4.0 中的动态类型对象上,方法分派是在运行时完成的,基于运行时类型。
C# 3.0 中的var
关键字意味着这个局部变量将是隐式类型,也就是说,不是程序员显式写下类型,而是类型系统会自行计算出来.这与动态类型无关,至少在 C# 3.0 中是这样。变量将是强静态类型的,就像您自己写下类型一样。这只是一种方便:例如,当类型系统可以清楚找出@987654324时,为什么还要在HashMap<int, string> foo = new HashMap<int, string>();
中写下所有类型名称两次 @ 是 HashMap<int, string>
,所以改为写 var foo = new HashMap<int, string();
。请注意,这没有任何动态或匿名的。该类型是静态的,并且有一个名称:HashMap<int, string>
。当然,在 C# 4.0 中,如果类型系统发现赋值的右侧是动态的,那么左侧变量的类型将是动态的。
C# 3.0 中的匿名类型 表示该类型没有名称。好吧,实际上,真正匿名类型需要对通用类型系统进行向后不兼容的更改,所以在幕后实际上发生的是编译器将生成一个非常类型的长,非常随机,唯一且非法的名称,并将该名称放在匿名类型出现的任何位置。但是从程序员的角度来看,类型没有名字。为什么这很有用?嗯,有时你有中间结果,你只需要短暂的,然后再扔掉。给这些瞬态类型起一个自己的名字会将它们提升到一个他们根本不应该得到的重要程度。但同样,这没有什么动态的。
那么,如果类型没有名字,程序员如何引用呢?好吧,她不能!至少不是直接的。程序员可以做的是描述类型:它有两个属性,一个称为string
类型的“名称”,另一个称为int
类型的“id”。那是我想要的类型,但我不在乎它叫什么。
这就是各个部分开始融合的地方。在 C# 中,您必须通过显式写下类型名称来声明局部变量的类型。但是,你怎么能写下一个没有名字的类型的名字呢?这就是 var
出现的地方:因为从 C# 3.0 开始,这实际上不再正确:您不再需要写下名称,您也可以告诉编译器来弄清楚。因此,虽然我在上面第一段中写的内容是正确的,隐式类型和匿名类型与其他类型没有任何关系,但如果没有隐式类型,匿名类型也将毫无用处。
但是请注意,相反的情况并非如此:隐式类型在没有匿名类型的情况下非常有用。 var foo = HashMap<int, string>
非常合理,而且看不到匿名类型。
【讨论】:
多么棒的答案!这是我在遇到这个问题并且您已经交付时想要的信息。谢谢!【参考方案2】:匿名类型是为您创建的真实的、编译器生成的类型。这样做的好处是编译器可以在稍后将这种类型重新用于需要它的其他操作,因为它是一个 POCO。
我对动态类型的理解是它们是后期绑定的,这意味着 CLR(或 DLR)将在执行时评估对象,然后使用鸭子类型来允许或禁止成员访问该对象。
所以我想区别在于匿名类型是编译器可以看到但您只能使用的真正 POCO,而动态类型是后期绑定的动态对象。
【讨论】:
【参考方案3】:dynamic
类型本质上是 object
,但会在运行时通过 DLR 或其他提供程序(例如反射)解析所有方法/属性/运算符等调用。
这使它很像带有Option Strict Off
的 VB,并且使它非常适用于调用 COM 或 DLR 类型。
在编译时有没有动态类型检查;很明显,匿名类型是正确的静态类型、类型检查的野兽(你可以在反射器中看到它们,尽管它们并不漂亮)。
此外,匿名类型可以由编译器专门处理; dynamic
需要广泛的运行时支持 - 因此匿名类型是 C# 功能,但 dynamic
将主要由 .NET 4.0 实现(支持一些 C# 4.0)。
【讨论】:
【参考方案4】:一共有三个时间,三个演员 - 每次一个。
设计时 - 程序员 编译时 - c# 编译器 运行时 - .net 运行时匿名类型由编译器声明和命名。此声明基于程序员的规范(他如何使用类型)。由于这些类型是在程序员离开进程后命名的,因此它们对程序员来说似乎是无名的,因此是“匿名的”。
程序员说:某些类型有名称和地址 编译器说:有一个名为 xyz 的类型,具有名称和地址属性和字段,都是字符串。 运行时说:我无法区分 xyz 和程序员制作的任何类型。c# 中的动态类型允许您调用在编译时可能存在或不存在的方法。这对于调用未编译的 python 或 javascript 很有用。
程序员说:将此汽车实例视为动态类型。现在,嘎嘎。 编译器说:动态类型是吗?一定没问题。我不会抱怨,因为我无法检查。 运行时尝试使 car 实例发出嘎嘎声。【讨论】:
【参考方案5】:没有什么比一个小代码更能解决问题了:
// 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");
【讨论】:
以上是关于匿名类型与动态类型的主要内容,如果未能解决你的问题,请参考以下文章