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中提供的类库,那么没办法,只能扩展方法。

 
 
分类: C#相关
 
0
0
 
(请您对文章做出评价)
 
posted @ 2009-05-29 14:29 飞林沙 阅读(2450) 评论(20) 编辑 收藏

 
评论列表
 
  

#1楼 2009-05-29 14:42 徐少侠

国内的培训学校的教师能力的确值得怀疑

不过,远离不是解决问题的办法

我就在培训机构工作

我希望让学生学习最基础的,了解最流行的,理解变迁的本质

  

#2楼 2009-05-29 14:46 Gray Zhang

请问泛型有效率影响的证据?从我的理解上,泛型是生成新的类型,拿来的效率影响之说呢
  

#3楼 2009-05-29 15:14 winter-cn未登陆[未注册用户]

我们都知道var只能用于变量,而无法用于属性,而我们使用var的情况往往是因为我们不大容易确定某一个变量(或者属性)的类型,同样,很可能出现一个类的属性或者方法返回类型不易确定返回类型的情况,这个时候,我们就可以用dynamic了。
----------------------------------------------------------
你的这个理解也是有些问题的 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

我也用List<Object>,因为有用的扩展方法都是加载IEnumerable<T>上的,ArrayList不行。
所以我现在也一直推荐说,情愿用List<Object>也不要用ArrayList。
至于性能,真有影响吗?我去试试看,我目前认为是一样的,因为其实是一样的代码阿。

http://pic.cnitblog.com/face/u9419.png

  

#6楼 2009-05-29 15:41 Gray Zhang

期待老赵的结论,数组其实也是特殊的泛型吧…
  

#7楼 2009-05-29 15:41 Gray Zhang

期待老赵的结论,数组其实也是特殊的泛型吧…
  

#8楼 2009-05-29 16:05 Jeffrey Zhao

@Gray Zhang
呵呵,得出结果了,正在写文章呢。

http://pic.cnitblog.com/face/u9419.png

  

#9楼[楼主] 2009-05-29 16:10 飞林沙

@winter-cn未登陆

嗯,呵呵,是的,我语言表达能力有些问题,当然,每个方法都有着他自己的返回类型,我们可以确定。但是有时写起来比较麻烦

http://pic.cnitblog.com/face/u35999.jpg

  

#10楼 2009-05-29 16:51 Jeffrey Zhao

性能比较结果如下:http://www.cnblogs.com/JeffreyZhao/archive/2009/05/29/generic-performance-test.html

结论:范型不会影响性能。

http://pic.cnitblog.com/face/u9419.png

  

#11楼 2009-05-29 17:32 xiaotie

不明白泛型的嵌套为什么会引起代码的膨胀

http://pic.cnitblog.com/face/u6006.jpg

  

#12楼[楼主] 2009-05-29 17:42 飞林沙

@Jeffrey Zhao

老赵,给我些时间,我找一下之前做过的一个笔记,确实有这样的印象。

http://pic.cnitblog.com/face/u35999.jpg

  

#13楼[楼主] 2009-05-29 17:43 飞林沙

@xiaotie

每个类型都生成不同的方法表,这是其一。
我之前做过一个完整的泛型方面的笔记,我回去找下,然后再补充

http://pic.cnitblog.com/face/u35999.jpg

  

#14楼 2009-05-29 17:47 Jeffrey Zhao

@飞林沙
List<T>,如果T是值类型,的确是每个值类型是不同的代码。但是如果T是引用类型,那么就是共享同一份代码的。
还有其实就算是引用类型,范型也可以减少cast啊,而且编程也爽多了。

http://pic.cnitblog.com/face/u9419.png

  

#15楼 2009-05-29 19:02 xiaotie

@飞林沙

泛型应该是减少代码的。

要实现同等功能,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

  

#16楼[楼主] 2009-05-29 19:19 飞林沙

@Jeffrey Zhao
@xiaotie

我在这里也没什么根据了,我先把我这一节跟注释掉,等明天找到了依据再和你们吵,哈!

http://pic.cnitblog.com/face/u35999.jpg

  

#17楼 2009-05-29 21:50 JimLiu

其实还是会很有用的,比如有时候直接var ...一个linq出来的匿名类型,这时候就能以dynamic的形式传给View了。
当对性能不是如此敏感的时候,显然比定义一个ViewModel类型敏捷了不少——当然,用强类型还是有其好处的。
再到做Silverlight这类的时候,有了dynamic也许也会方便很多。上次那个session(忘了是什么活动的)里的demo就有这么点体会。

http://pic.cnitblog.com/face/u35553.jpg

  

#18楼 2009-05-30 01:44 clayman

泛型实际上有时候性能更好http://blogs.msdn.com/ricom/archive/2005/08/26/performance-quiz-7-generics-improvements-and-costs-solution.aspx
泛型确实会导致一定的代码膨胀,编译器有时候需要为不同的特定类型,生成不同的代码
  

#19楼 2009-05-30 09:26 Muse

我用var就是为了偷懒,比如foreach Dictionary的时候.
我觉得dynamic还有一个用法,比如我需要一个方法返回不同类型的对象,而这些对象来源于同一个地方,我只是要根据不同的环境返回不同的属性(比如给一个ID,根据需要返回一个对象的不同属性),这时用dynamic的话,只需要一个方法,然后加一个参数,而不需要些若干相似的方法了。
  

#20楼15419402009/5/30 18:52:54 2009-05-30 18:52 装配脑袋

@xiaotie
where过多,过长,都是错误使用泛型的例子。例如
void T Create<T>() where T: ISomething, new
八成都是错的用法。更别提约束一大堆接口了。约束的目的是减少可用的类型,而不是提供接口和基类的成员,如果不是本着这个原则使用约束,就必定是将本应该用OO解决的问题让泛型来解决了。

.NET,你忘记了么?(八)—— 从dynamic到特性误用 [转]的更多相关文章

  1. 设计模式(八)Dynamic Proxy Parttern 动态代理模式

    举例: jdk自带动态代理 javaassit字节码操作库实现 CGLIB ASM底层操作 实际例子: 使用jdk自带动态代理 java.lang.reflect.Proxy 作用 动态生成代理类和对 ...

  2. C# 新特性 dynamic的使用及扩展

    个人而言感觉C#的dynamic是一个特别实用的东西,为日常开发工作中的封装,数据传递等带来了很高的可扩展性. C#4.0中通过对数据类型后期绑定的支持,演化出了dynamic.任何直接声明为这种类型 ...

  3. Spark中的Phoenix Dynamic Columns

    代码及使用示例:https://github.com/wlu-mstr/spark-phoenix-dynamic phoenix dynamic columns HBase的数据模型是动态的,很多系 ...

  4. dynamic

    dynamic的特性很多,好像和反射也有关,不过这里先介绍一个特性,关于反射的再补充. 我们来看一个方法: public virtual ActionResult Insert(T info) 有一个 ...

  5. 利用dynamic简化数据库的访问

    今天写了一个数据库的帮助类,代码如下. public static class DbEx { public static dynamic ReadToObject(this IDataReader r ...

  6. Linux 内核引导选项简介

    Linux 内核引导选项简介 作者:金步国 连接地址:http://www.jinbuguo.com/kernel/boot_parameters.html 参考参数:https://www.cnbl ...

  7. 进阶系列(10)—— C#元数据和动态编程

    一.元数据的介绍 元数据是用来描述数据的数据(Data that describes other data).单单这样说,不太好理解,我来举个例子.下面是契诃夫的小说<套中人>中的一段,描 ...

  8. 值得尝试的十款 GNOME Shell 扩展

    值得尝试的十款 GNOME Shell 扩展 作者: JACK WALLEN 译者: 核子可乐 | 2016-09-22 17:10   评论: 6 收藏: 1 当 GNOME Shell(即 GNO ...

  9. null==a和a==null的区别

    在项目代码中在if判断中会经常看到一些老司机这样写:if(null == a),而我由于习惯会写成if(a == null),这两种有什么区别呢? 其实两种并没有什么区别,只是前者在细节处理上.我们在 ...

随机推荐

  1. COB對PCB設計的要求

    由於COB沒有IC封裝的leadframe(導線架),而是用PCB來取代,所以PCB的焊墊設計就便得非常的重要,而且Fihish只能使用電鍍金或是ENIG(化鎳浸金),否則金線或是鋁線,甚至是最新的銅 ...

  2. Visual Studio 2015 Update 3 RC 候选预览版粗来了

    .Net 基金会 http://www.dotnetfoundation.org/ 更新的真快,刚打完2的补丁包,3就粗来了............ https://www.visualstudio. ...

  3. linux之SQL语句简明教程---主键,外来键

    主键 (Primary Key) 中的每一笔资料都是表格中的唯一值.换言之,它是用来独一无二地确认一个表格中的每一行资料.主键可以是原本资料内的一个栏位,或是一个人造栏位 (与原本资料没有关系的栏位) ...

  4. [SQL]一个删选数据的例子,使用GROUP、DISTINCT

    今天遇到的问题,纠结了一上午,终于解决了.在此记录下来,自我认为还有很多类似的问题都可以套用这段代码. 需求描述: 一个表MyImage,列有:号码ID,路径PATH 如: ID  PATH 1  C ...

  5. 网易云课堂_C++开发入门到精通_章节2:引用和函数的高级用法

    课时6函数重载 函数重载 在C语言头文件中的extern "C" //常见的C语言头文件格式 #ifndef _FUNC_ #define _FUNC_ #ifdef __cplu ...

  6. Codeforces 551C GukiZ hates Boxes 二分答案

    题目链接 题意:  一共同拥有n个空地(是一个数轴,从x=1 到 x=n),每一个空地上有a[i]块石头  有m个学生  目标是删除全部石头  一開始全部学生都站在 x=0的地方  每秒钟每一个学生都 ...

  7. 聚类算法初探(五)DBSCAN

    最近由于工作需要,对聚类算法做了一些相关的调研.现将搜集到的资料和自己对算法的一些理解整理如下,供大家参考. 另外在算法代码方面,我也做了一些实现(包括串行和并行),欢迎感兴趣的朋友探讨和交流. 第一 ...

  8. ps怎样选取自己想要的图片部分(二)

    上篇文章我们介绍了怎样选取所要的图形.但往往我们实际做项目的时候须要创建一个圆形图标或者椭圆形图标,这样会使得我们的图标相比矩形图标更加美观一些. 那么怎样将一个矩形图标改成圆形图标呢? 首先我们须要 ...

  9. 位运算 (&|)与--或 一位数组表示多种意思~~ 与--或

    var arr:Array = [0,1,2,4,8,16] var gate:int = 0; gate |= arr[1] gate |= arr[2] gate |= arr[3] trace( ...

  10. 从U盘安装win8系统

    http://blog.csdn.net/pipisorry/article/details/40662397 lz提示,下面也能够用于win7.linux等操作系统的安装 一.下载windows安装 ...