var与dynamic
如果你用MVC写过程序,那么你应该知道ViewBag这个用于前后台的数据传递工具,那么你是否对ViewBag的用法感到过疑惑呢?
ViewBag.Mode1l=newobject();
ViewBag.Model2=newobject();
ViewBag.Model3=newobject();
......
我们知道,在使用对象属性的时候要先申明(即这个对象的类中已经定义了这个属性)才能使用(此时VS的自动提示能弹出此类的所有属性),然而使用ViewBag时你会发现ViewBab.之后不会弹出任何属性(除非前面已经添加了属性),而且我们可以自己随便写一个属性,却可以正确运行。而这都是归功于dynamic这个属性。
1.在讲dynamic之前,先来回顾一下var这个类型。
从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var。隐式类型的本地变量是强类型变量(就好像您已经声明该类型一样),但由编译器确定类型。下面的两个i 声明在功能上是等效的:
vari =10;//implicitly typed(隐式申明)inti =10;//explicitly typed(显示申明)
var这个类型是通过编译器确定的(即在编译时,编译器会根据这个变量的值或引用的对象类型来决定这个变量的类型),但要注意一旦这个变量的类型确定了之后就不可在更改。
vari =1;//i为int型, 等价于 int i = 1;i =1.0;//报错,1.0为double型
注意,var型变量在申明时必须初始化,如下:
vari =1;//正确vari;
i=1;//错误
2.var用法举例:
// 允许但不需要使用var,因为可以将查询结果的类型显示的申明为IEnumerable<string>string[]Words = {"apple","strawberry","grape","peach","banana"};varwordQuery =fromwordinwordswhereword[0] =='g'selectword;//因为元素类型为string类型,不是匿名类型,所以var是非必需的foreach(stringsinwordQuery)
{
Console.WriteLine(s);
}//表达式中必须使用var,因为结果是一个匿名类型集合,而该类型的名称只有编译器本身可以访问varcustQuery =fromcustincustomerswherecust.City =="Phoenix"selectnew{ cust.Name, cust.Phone };//foreach 迭代变量item 也必须转换为隐式类型,因为custQuery为匿名集合foreach(varitemincustQuery)
{
Console.WriteLine("Name={0}, Phone={1}", item.Name, item.Phone);
}
3.dynamic
在通过dynamic 类型实现的操作中,该类型的作用是绕过编译时类型检查,改为在运行时解析这些操作。dynamic 类型简化了对 COM API(例如 Office Automation API)、动态 API(例如 IronPython 库)和 HTML 文档对象模型 (DOM) 的访问。
在大多数情况下,dynamic 类型与object 类型的行为是一样的。但是,不会用编译器对包含dynamic 类型表达式的操作进行解析或类型检查。编译器将有关该操作信息打包在一起,并且该信息以后用于计算运行时操作。在此过程中,类型dynamic 的变量会编译到类型object 的变量中。因此,类型dynamic 只在编译时存在,在运行时则不存在。
classPRogram
{staticvoidMain(string[] args)
{dynamicdyn =1;objectobj =1;
dyn= dyn +3;//编译可以通过,dynamic可以绕过编译器obj = obj +3;//报错,编译无法通过System.Console.WriteLine(dyn.GetType());
System.Console.WriteLine(obj.GetType());
}
}//输出结果System.Int32
System.Int32
4.dynamic一些常见的用法
(1)在声明中,作为属性、字段、索引器、参数、返回值或类型约束的类型。
classExampleClass
{//字段staticdynamicfield;//属性dynamicprop {get;set; }//返回值与参数publicdynamicexampleMethod(dynamicd)
{dynamiclocal ="Local variable";inttwo =2;if(disint)
{returnlocal;
}else{returntwo;
}
}
}
(2)在显式类型转换中,作为转换的目标类型。
staticvoidconvertToDynamic()
{dynamicd;inti =20;
d= (dynamic)i;
Console.WriteLine(d);strings ="Example string.";
d= (dynamic)s;
Console.WriteLine(d);
DateTime dt=DateTime.Today;
d= (dynamic)dt;
Console.WriteLine(d);
}//Results://20//Example string.//2/17/2009 9:12:00 AM
(3)在以类型充当值(如is 运算符或as 运算符右侧)或者作为typeof 的参数成为构造类型的一部分的任何上下文中。
inti =8;dynamicd;if(someVarisdynamic) { }d = iasdynamic;Console.WriteLine(typeof(List<dynamic>));//Console.WriteLine(typeof(dynamic));//编译错误
5.dynamic与ViewBab
ViewBab是一个dynamic类型的属性,所以编译器不会对它进行检查,所以我们可以自定义属性。我们也可以通过ExpandoObject() 这个类来实现我们自己的ViewBab,看下面示例:
publicclassProgram
{publicstaticvoidMain(string[] args)
{dynamicmodel =newExpandoObject();//在运行时,model 会转化为 ExpandoObject() 的一个实例model.Index =0;//ExpandoObject() 有一个事件 PropertyChanged,运行时动态触发这个事件,model.Number =0;//然后将Index与Number这个两个属性添加到类中Console.WriteLine(model.Index);
Console.WriteLine(model.Number);
Console.ReadKey();
}
}
也许你会觉得dynamic用到的不多,所以不必深入理解,但等到你真正遇到它时,将会吃大亏。正如上面讲的那样,它在COM API 、 动态API 、HTML对象模型的操作上有重要作用,通过它,可以简化操作,但同时它也容易让人迷糊(它所指向的究竟是什么样的对象类型),因为简化通常意味着隐藏,它将复杂的后台实现封装并开放见简单的接口给我们使用,这样简化了我们的操作,却然我们更容易迷惑,我们不知道它为什么要这样做,只知道可以这样做,使得我们在很多问题上无法深入挖掘。在网站开发中,深入理解dynamic,有利于我们深入到框架内部去,对我们学习.Net架构是非常有帮助的。