代码改变世界

艾伟:.NET,你忘记了么?(八)-- 从dynamic到特性误用

2011-08-28 23:55  狼人:-)  阅读(135)  评论(0编辑  收藏  举报

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的情况:

image

接下来是dynamic:

image

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#代码数量也许就能吓到你了:

image

5. 从误用继续说开去

任何一种事物永远都是双面性的,同样,任何一种新鲜事物的产生总是会有着他的利和他的弊。究竟是利还是弊,其本质原因不在于他本身,而在于他周围的环境对他的使用是利大于弊,还是利小于弊。

任何一个C#新语言特性也是亦然。而他周围的环境就是我们程序员。

我看到过太多太多的误用,比如对泛型的误用,对委托的误用,对扩展方法的误用。

在这里就再谈谈扩展方法的误用。

6. 何时扩展方法

我在中提过Prototype的缺点,在这里我只说一点:能够动态地添加属性和方法固然是增加了灵活性。可是我们讨论一种情况,100个人同时来开发一个Javascript的项目,很多没经验的人爱上了玩转prototype,一个人往这个类里加一个方法,还面向对象么?

扩展方法也是一样,100个开发者同时去开发一个项目,每个人都写一个扩展方法,那么这个项目会乱成什么样大家可想而知。

那么什么时候该用扩展方法,我个人认为只有三种情况:

A. 你独立负责一个组件的编写,而这个组件需要调用其他组件中的类,而你常常需要用到某个类中的某个他并为提供的“方法”。那么这个时候,你可以在你的组件内特殊放置一个类,用来容纳你所需的扩展方法。

B. 一个团队面对的一个已经封装好的组件,但是某个方法是这个组件没有提供的,重写组件实在麻烦,那好吧。扩展方法。

C. 其实这个与第二点有些相似,当你面对的是.NET Framework中提供的类库,那么没办法,只能扩展方法。

7. 总结

其实误用的根本就在于知其然而不知其所以然,在这里,就说明情况,实在懒着浪费唇舌去抨击那些不值得我一抨击的培训学校了。

珍爱生命,远离培训。这是我唯一的劝告。