.NET,你忘记了么?(八)—— 从dynamic到特性误用 [转]
1. 摘要
每个程序员都想写出漂亮的代码,但是什么是漂亮,这个我想每个人都有着自己的看法。那么我就说几种典型的想法:
A. 写出别人看不懂的代码,让别人觉得很高深。
B. 写出简短的代码
C. 用最新的语言特性写出代码
这个我不发表评论,毕竟每个人有着自己的观点,我也不能证明自己的就是对的。但是在这里,我想说一些典型的误用。
2. 从dynamic谈起
作为C#4.0的更新之一,dynamic已经越来越被推到了很多技术论坛的第一线。我看了很多关于dynamic的讲解,但是我还是我一贯的观点。既然我们用的微软的东西,那么我们在使用一个语言特性的同时,我们首先要弄清微软为什么要推出这门语言,不要盲目去使用。这样往往会适得其反。
那下面我就看大多数教程中的一个传统代码:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
dynamic p = new People("Test");
Console.WriteLine(p.GetName());
}
}
class People
{
private string name;
public string GetName()
{
return name;
}
public People(string name)
{
this.name = name;
}
}
}但是正如很多评论中的质疑的一样,这样的操作究竟有什么作用?(我并不是怀疑很多作者不懂这个,而是说这个会误导很多人)于是很多人就会不明不白地去跟风,去乱用dynamic。
那么我们就在这里说清,究竟为何dynamic。
3. dynamic和var
在说这两个关键字之前,我们要先搞清楚两个概念。什么叫强类型语言,什么叫弱类型语言。
一句经典的话我想最能解释他们的区别了:static typing when possible,dynamic typing when needed.
其实也就是说:静态语言是在编译时确定类型,而弱类型是在运行时确定类型。
一个简单的例子就能看出他们的区别:
首先是使用var的情况:
接下来是dynamic:
4. 究竟为何dynamic
在国外某博客中,我记得有这样一个说法,是说dynamic会颠覆传统的C#编程方式,从前说世间万物皆为对象,那么现在世间对象皆为dynamic。
class People
{
private dynamic name;
public People(dynamic name)
{
this.name = name;
}
public dynamic Introduce()
{
dynamic s = "Hello,I am" + name;
return s;
}
public delegate dynamic Notify(dynamic argument);
}不过,就我个人而言,并不认同这种说法,已经有很多《“深入剖析”dynamic》之类的文章了,我就不在多写了。总之dynamic会对效率产生很大的影响。如果这样滥用dynamic:
A. 对程序的效率有很大影响
B. Visual Studio 强大的智能感知功能被完全废弃了。
既然这样,那么我们为什么要使用dynamic,就我的理解而言:
A. 语言的互操作,比如去调用C++的一个Com组件,我们完全可以用dynamic取代反射略显复杂的语法。
B. 我们都知道var只能用于变量,而无法用于属性,而我们使用var的情况往往是因为我们不大容易确定某一个变量(或者属性)的类型,同样,很可能出现一个类的属性或者方法返回类型不易确定返回类型的情况,这个时候,我们就可以用dynamic了。比如:
public dynamic GetAllGrilFriendsDetails()
{
var gfDetails = from o in db.People
where o.name = this.name
select new
{
Name = o.firstName + o.lastName,
Age = o.age,
Address = o.address
};
return gfDetails;
}为什么我在方法内部去用 dynamic gfDetails,如果你讨厌去看IL代码细节,那么我们只看由于dynamic产生的反编译C#代码数量也许就能吓到你了:
5. 从误用继续说开去
任何一种事物永远都是双面性的,同样,任何一种新鲜事物的产生总是会有着他的利和他的弊。究竟是利还是弊,其本质原因不在于他本身,而在于他周围的环境对他的使用是利大于弊,还是利小于弊。
任何一个C#新语言特性也是亦然。而他周围的环境就是我们程序员。
我看到过太多太多的误用,比如对泛型的误用,对委托的误用,对扩展方法的误用。
在这里就再谈谈扩展方法的误用。
6. 何时扩展方法
我在<Javascript玩转Prototype(二) >中提过Prototype的缺点,在这里我只说一点:能够动态地添加属性和方法固然是增加了灵活性。可是我们讨论一种情况,100个人同时来开发一个Javascript的项目,很多没经验的人爱上了玩转prototype,一个人往这个类里加一个方法,还面向对象么?
扩展方法也是一样,100个开发者同时去开发一个项目,每个人都写一个扩展方法,那么这个项目会乱成什么样大家可想而知。
那么什么时候该用扩展方法,我个人认为只有三种情况:
A. 你独立负责一个组件的编写,而这个组件需要调用其他组件中的类,而你常常需要用到某个类中的某个他并为提供的“方法”。那么这个时候,你可以在你的组件内特殊放置一个类,用来容纳你所需的扩展方法。
B. 一个团队面对的一个已经封装好的组件,但是某个方法是这个组件没有提供的,重写组件实在麻烦,那好吧。扩展方法。
C. 其实这个与第二点有些相似,当你面对的是.NET Framework中提供的类库,那么没办法,只能扩展方法。
#2楼 2009-05-29 14:46 Gray Zhang
#3楼 2009-05-29 15:14 winter-cn未登陆[未注册用户]
----------------------------------------------------------
你的这个理解也是有些问题的 var其实本质是懒得写类型 让编译系统自动帮你决定 所以问题不是出在属性或者局部变量上
dynamic把对类型的检测延迟到运行时 dynamic最主要的意义还是改进封装性 使得你能够编写更加灵活通用代码 同时运行时检测类型并捕获异常 可以真正做到duck type
其实可以想到 dynamic有很多有趣的用法 比如跟匿名委托配合
#4楼 2009-05-29 15:16 winter-cn未登陆[未注册用户]
Gray Zhang: 请问泛型有效率影响的证据?从我的理解上,泛型是生成新的类型,拿来的效率影响之说呢
--------------------------------------------------------
.net的泛型会略微影响效率 跟C++略有些不同
#5楼 2009-05-29 15:26 Jeffrey Zhao
#6楼 2009-05-29 15:41 Gray Zhang
#7楼 2009-05-29 15:41 Gray Zhang
#8楼 2009-05-29 16:05 Jeffrey Zhao
#10楼 2009-05-29 16:51 Jeffrey Zhao
结论:范型不会影响性能。
http://pic.cnitblog.com/face/u9419.png
#14楼 2009-05-29 17:47 Jeffrey Zhao
泛型应该是减少代码的。
要实现同等功能,ClassA<Type> where Type : IInterfaceA 大致等同于
ClassA
{
public IInterfaceA A {get;set;}
}
用泛型写要少写很多代码。
如果是 Class<TType1<TType2<TType3<TType4>>>> 这样的泛型,节省的代码就更多了。
编译后的代码大小,老赵上面也说了。
C#下泛型烦在写的时候太麻烦。
像写个Class<TType1<TType2<TType3<TType4<TType5<TType6<TType7<TType8<TType9>>>>>>>>> 这样的泛型类,光写 where 能把人折腾死。
http://pic.cnitblog.com/face/u6006.jpg
泛型确实会导致一定的代码膨胀,编译器有时候需要为不同的特定类型,生成不同的代码
.NET,你忘记了么?(八)—— 从dynamic到特性误用 [转]的更多相关文章
- 设计模式(八)Dynamic Proxy Parttern 动态代理模式
举例: jdk自带动态代理 javaassit字节码操作库实现 CGLIB ASM底层操作 实际例子: 使用jdk自带动态代理 java.lang.reflect.Proxy 作用 动态生成代理类和对 ...
- C# 新特性 dynamic的使用及扩展
个人而言感觉C#的dynamic是一个特别实用的东西,为日常开发工作中的封装,数据传递等带来了很高的可扩展性. C#4.0中通过对数据类型后期绑定的支持,演化出了dynamic.任何直接声明为这种类型 ...
- Spark中的Phoenix Dynamic Columns
代码及使用示例:https://github.com/wlu-mstr/spark-phoenix-dynamic phoenix dynamic columns HBase的数据模型是动态的,很多系 ...
- dynamic
dynamic的特性很多,好像和反射也有关,不过这里先介绍一个特性,关于反射的再补充. 我们来看一个方法: public virtual ActionResult Insert(T info) 有一个 ...
- 利用dynamic简化数据库的访问
今天写了一个数据库的帮助类,代码如下. public static class DbEx { public static dynamic ReadToObject(this IDataReader r ...
- Linux 内核引导选项简介
Linux 内核引导选项简介 作者:金步国 连接地址:http://www.jinbuguo.com/kernel/boot_parameters.html 参考参数:https://www.cnbl ...
- 进阶系列(10)—— C#元数据和动态编程
一.元数据的介绍 元数据是用来描述数据的数据(Data that describes other data).单单这样说,不太好理解,我来举个例子.下面是契诃夫的小说<套中人>中的一段,描 ...
- 值得尝试的十款 GNOME Shell 扩展
值得尝试的十款 GNOME Shell 扩展 作者: JACK WALLEN 译者: 核子可乐 | 2016-09-22 17:10 评论: 6 收藏: 1 当 GNOME Shell(即 GNO ...
- null==a和a==null的区别
在项目代码中在if判断中会经常看到一些老司机这样写:if(null == a),而我由于习惯会写成if(a == null),这两种有什么区别呢? 其实两种并没有什么区别,只是前者在细节处理上.我们在 ...
随机推荐
- poI地址纠偏查询存储过程理解
1.POI存储过程查询 服务器类型:PostgreSQL function name 函数名字 address_parse_no_save(lon float8, lat float8) DECLAR ...
- 续前篇---数据挖掘之聚类算法k-mediod(PAM)原理及实现
上一篇博文中介绍了聚类算法中的kmeans算法.无可非议kmeans由于其算法简单加之分类效率较高 已经广泛应用于聚类应用中. 然而kmeans并非十全十美的.其对于数据中的噪声和孤立点的聚类带来的误 ...
- linux监控脚本,脚本支持传参,整合C程序
1,查看指定用户下的进程pid
- wxpython 拖动界面时进入假死状态(未响应)解决方法
场景:在一个事件中调用一个函数,但是这个函数执行的时间非常的长,此过程中拖动界面的时候会使得界面进入未响应状态,直到函数执行完才可以ok 解决方法: 在调用函数的时候使用多线程调用 import th ...
- 依赖注入及AOP简述(七)——FQCN请求模式
2.2. FQCN请求模式 为了弥补纯字符串请求模式中的类型安全问题,全类名(FQCN)请求模式就应运而生了.其思想便是,在向容器请求依赖对象的时候,不是通过字符串的标识符.而是通过被请求的依赖 ...
- 模块化的JavaScript
我们再一次被计算机的名词,概念笼罩. backbone.emberjs.spinejs.batmanjs 等MVC框架侵袭而来. CommonJS.AMD.NodeJS.RequireJS.SeaJS ...
- 绿色mysql启动脚本
启动脚本如下:./mysqld_safe --defaults-file=/export/servers/mysql-5.5.38/my.cnf --ledir=/export/servers/mys ...
- Apache Lens —— 统计数据分析查询接口
Lens 提供了一个统一数据分析接口.通过提供一个跨多个数据存储的单一视图来实现数据分析任务切分,同时优化了执行的环境.无缝的集成 Hadoop 实现类似传统数据仓库的功能. 该项目主要特性: 简单元 ...
- UVA 1615 Highway
题意: 有一条沿x轴正方向,长为L的高速公路,n个村庄,要求修建最少的公路出口数目,使得每个村庄到出口的距离不大于D. 分析: 每个村子可建出口的距离是(l-d,r+d).将所有区间按右端点排序,若需 ...
- ProgressBar、RatingBar和Spinner控件
1.ProgressBar.SeekBar与RatingBar控件 ProgressBar控件,也就是我们通常的进度条控件,可以显示加载的进度等.SeekBar控件,滑块控件,可以根据用户的需要动态为 ...