C#中var与dynamic之间的区别和匿名类型使用方法

717 阅读5分钟
分享此文仅限对程序员有兴趣的朋友,如本中有错误的理解,请大家指正,在后期我会不定时的更新C#中比较有实践操作的知识,与大家共同交流,共同进步。
在C#中,大多数程序员都使用过var关键字和匿名类型,如题,在此文多添加了一个dynamic类型,本文重点也就是讲dynamic的作用。
var在C#中的出现,给程序带来了很大的便利,如下图: 

在var修饰的变量中,不管你给什么值,都会自动编译时确定其类型,不用考虑变量是int、double、string类型,那么dynamic呢?

根据上面两个图比较,dynamic和var是做着相同的工作,但是开发人员是不可能做这么无聊的开发设计的,那么dynamic具体有什么作用呢?

根据上图,可以明显的看到它们之间的差异,由此可以说明在对var变量赋值时,就已经确定其变量的类型,dynamic是一种运行时动态类型的变量,大家都知道C#是一种面向对象的语言,那么dynamic它在C#里面的出现有什么意义呢?后面我会讲到dynamic的实用技巧,在这里,根据上面的图片说明,可以确定var与dynamic的区别,如下:
var : 

 1、var 声明变量,不能赋NULL值。

 2、var 赋值后,编译时确定了类型。 

 3、var简化了类型声明。 

dynamic: 

 1、dynamic是运行时动态类型。

 2、dynamic支持弱对象。 

 3、dynamic可以随意修改变量值。 

 4、dynamic可以赋有NULL值。

接下来,我们在深入的看下dynamic的作用,dynamic肯定不是微软大神们给程序员们设计出来的玩具,肯定还有其它用途,大家肯定想到了,匿名对象!具体var和dynamic在匿名对象上使用有什么区别呢?如下图:

根据上面两个图,大家可以清楚的知道为什么我会说 var是赋值后编译器就确定了的类型,而dynamic是运行时动态类型,貌似它们在匿名对象除了这点区别外,没有其它作用了,非然,我不知道大家在做项目的时候,有没有发现当数据库字段非常多的时候,而UI界面只是显示其中几个字段而已,根据框架设计理念,大多数项目会把数据库中的Table封装成Modelor Entity ,大多数程序员会把Model层设计成如下图:

在这两种设计模式中,因为都是属于实体层,而在控制层当中查询到两表数据后,显示到UI层里面,程序员会相当痛苦的写着。
在这两种模式中,使用模式一的程序员还好,使用模式二中的程序员肯定很苦,然而,UI中在显示数据时,并不是所有的字段都需要,给服务器内存造成很大的浪费,大家马上会想到匿名对象和var的使用(假如我们这里只要A表的Id、Money,B表的OtherField):
例1:
vardb_1 = new ArrayList();
db_1.add(new{Id = A.Id , Money = A.Money, OtherField = B.OtherField});
这种写法节省了内存,也很便利,但是在真实的项目中,不实用!因为很多项目都是MVC模式开发,会有一个数据层,控制层,View层,上面“例1”中的写法,大多数是在数据层去添加并返回的,db_1里面全是匿名对象,如何在控制层去使用匿名对象?大家肯定会说不是还有struct构造函数吗?确实,struct确实可以解决这类问题,但是个人觉得使用struct来完成这项工作实在是太累了,比如说:一个项目有100多种视图呢?难道要声明100多种struct构造函数吗?所以dynamic的实用技巧体现出来了!参考下图:

根据上面两张图片,大家肯定很清楚的知道var与dynamic的具体区别与用途了,那么,我们的程序运行起来,会有什么效果呢? 

运行之后,会显示RuntimeBinderException错误,提示object未包含Id的定义,而我们明显看到view下面是有Id字段的,并且有值,这是为什么呢?其实这是匿名对象引起的,当我们创建一个类的时候,会声明Class是否public、Internal,但是匿名类型我们无法去声明对象是什么访问级别,我们现在用MSIL看下我们的匿名类型,如下图:

如上图MSIL反射出来的匿名对象,我们可以清楚的看到匿名对象并不是真实的没有对象类型,而是由编译器自动给定类型名称,并且访问级别是private,这样,我们就清楚为什么我们访问view.Id会报“object未包含Id的定义”的错误了,接下来,我们来解决匿名对象访问级别问题,要想解决这类问题,我们必须依靠C#中的反射机制,具体参考下图:

此处代码是看到赵劼的一个文章才理解的。

我创建了一个Anonymous的类,并且增加了一个ToPublic的扩展函数,并且把getData()函数由List改成了List,现在 我们来看看我们的结果如何?
根据以上实验,已经很清楚var、dynamic所存在的差异,当然dynamic肯定不仅仅只限此类用途,但是,我要提醒大家在使用dynamic上面一定要谨慎,因为dynamic是一个动态运行时解析对象,很容易造成严重的Bug。
关于dynamic其它的高级应用需靠大家去发现。