Hello World
Spiga

Why Java Sucks and C# Rocks(补2):标准事件模型

2010-07-13 09:17 by 老赵, 5384 visits

这又是一篇“补”,本来并不想写这方面的内容,因为这并非完全是“语言”相关。打个比方,如果您觉得.NET中的事件模型不友好,那么就按Java的做法去做咯(反之就做不到了)。不过既然正好看到有些涉及到这方面的讨论,那么我也趁此机会发表一下自己的看法吧。这次谈的是两种语言(其实在这个话题上也是平台)下“标准”的事件模型。“标准”二字意味着是被双方社区各自接受的模型,而不仅仅是为了实现“事件”这一理念而使用的任意做法。

.NET中的事件

还是从两种事件模型开始介绍。首先是.NET中的事件模型。.NET里的“事件”是一等公民,换句话说,这是平台中所直接定义和描述的概念,我们利用反射相关的API(如GetEvent方法)可以直接获取到某个“事件”对象,然后对其进行各类操作(例如添加或删除处理器)。.NET中的事件基于“委托”,这也是.NET有别于Java平台的概念之一,在上一篇文章中也有过简单介绍,事实上委托在.NET 1.0中似乎完全是为事件量身定做的,例如在System.Windows.Forms.Form类中便定义了:

// C#
public class Form : Component
{
    public event MouseEventHandler MouseMove;
    public event MouseEventHandler MouseDown;
    public event MouseEventHandler MouseUp;
    public event MouseEventHandler MouseWheel;
    ...
}

当然“事件”这东西不光是UI组件独有的,事实上在.NET中有一种异步模式便是基于事件的——例如WebClient类,在使用时我们可以为一个WebClient对象的DownloadProgressChanged事件注册事件处理方法:

// C#
void Download()
{
    WebClient client = new WebClient();
    client.DownloadProgressChanged +=
        new DownloadProgressChangedEventHandler(OnDownloadProgressChanged);
    ...
}

void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    ...
}

在.NET中,事件的处理器是一个符合委托签名方法,单个事件之间完全分离,它们各自的事件处理器也完全独立。

Java中的事件

Java中并没有特定的“事件”对象,这和它的“属性”一样,都是属于纯粹“概念”上的内容,事实上它们完全是由普通的方法,接口等基本事物形成的。例如,同样作为UI组件中的窗口,javax.swing.JFrame有一套这样的API(继承自java.awt.Component):

// Java
public class Component {
    public void addMouseListener(MouseListener l);
    public void removeMouseListener(MouseListener l);
    public MouseListener[] getMouseListeners();
    ...
}

public interface MouseListener {
    void mouseClicked(MouseEvent e);
    void mouseEntered(MouseEvent e);
    void mouseExited(MouseEvent e);
    void mousePressed(MouseEvent e);
    void mouseReleased(MouseEvent e);
}

Java中的事件不是“对象”,如它的属性一样,都是“一组API”,不过事件比属性更复杂一些。Java中的事件模型由几个部分组成:一个addXxxListener方法,用于添加事件处理器;一个removeXxxListener方法用于删除一个事件处理器;还有一个getXxxListners方法用于获得当前已经添加的所有的事件处理器。此外,在Java中的事件处理器是由接口XxxListener表示的,一个接口中包含了多个事件,换句话说,Java是对事件进行了“分组”,例如在Component对象中还有另外一组与鼠标有关的事件:

// Java
public class Component {
    public void addMouseMotionListener(MouseMotionListener l);
    public void removeMouseMotionListener(MouseMotionListener l);
    public MouseMotionListener[] getMouseMotionListeners();
    ...
}

public interface MouseMotionListener {
    void mouseDragged(MouseEvent e);
    void mouseMoved(MouseEvent e);
}

在使用事件时,往往是利用匿名类型添加事件处理器,例如:

// Java
component.addMouseMotionListener(
    new MouseMotionListener() {
        public void mouseMoved(MouseEvent e) {
            // do this, do that...
        }
        public void mouseDragged(MouseEvent e) { /* empty */ }
    });

使用匿名类型,我们可以内联地创建一个实现了XxxListener接口的对象,这样就避免了创建一个新的类型(在Java语言中这意味着还要创建新的源文件),也方便形成一个能够访问上下文成员的闭包。不过您可以发现,如果我们只是要监听mouseMoved事件,也需要实现整个分组,即MouseMontionListener接口,只不过要将无需实现的方法留空罢了。这么做产生的问题就是,例如像MouseListener这样的接口,其中包含5个成员,那么如果我只想实现mouseClicked单个事件的话,留空其他4个方法还是太过麻烦了。因此Java也提供了对应的XxxAdaptor类,让我们可以写出这样的代码:

// Java
component.addMouseListener(
    new MouseAdaptor() {
        public void mouseClicked(MouseEvent e) {
            // do this, do that...
        }
    });

XxxAdaptor类会实现XxxListener接口,并且实现其中的所有方法,并全部留空。于是在使用时,我们便可以基于Adaptor类创建一个匿名类型,并选择我们需要的方法来覆盖(override)。例如上面这段代码,我们既然只要关注mouseClicked事件,那么也只要覆盖这一个方法就行了。

Java事件模型的缺点

一句话:我不喜欢Java的事件模型。

首先,Java的事件模型比较零散。一个事件要包含三个方法,这三个方法组成一个完整的事件,缺一不可。那么,这三个方法为什么就不能“一体化”,统一成单个对象呢?.NET在这方面做的比较好,事件本身是一个独立的对象,无论是添加、删除,还是获得当前所有的事件处理器,都是从“事件对象”本身出发的功能。这与“属性”一样,我认为.NET的设计更为紧凑,优雅。当然,要实现这一点,并非一定要.NET中“委托”这样有些特殊的类型,一个普通的接口或是抽象类也可以满足“单一对象”的要求。只是,我不是十分接受Java这种“松散”的事件模型。

其次,Java的事件之间不是独立,而是经过“分组”的——当然,也有像MouseWheelListener那样的只包含mouseWheel单个事件的“分组”,但毕竟大部分分组中还是包含多个事件。这就出现一个问题,我们难以单独处理单个事件,在添加单个事件的处理器时必然要涉及到其他事件。我们来设想这样一种情况:

// Java
component.addMouseListener(
    new MouseAdaptor() {
        public void mouseClicked(MouseEvent e) {
             // do this, do that...
        }
    });

component.addMouseListener(
    new MouseAdaptor() {
        public void mousePressed(MouseEvent e) {
             // do this, do that...
        }
    });

以上两段代码分别为mouseClicked和mousePressed事件各自添加了一个事件处理器。那么请问,当mouseClicked事件触发时,将会执行几个事件处理器?答案是2个,一个是我们添加的逻辑,还有一个是随mousePressed事件一起携带而来的“空白逻辑”。而且事实上,即便是理应“置身事外”的mouseEntered或mouseExited事件,它们也被各自添加了两个空白的处理器。对于一个对性能极度苛刻的程序员来说,这样的“浪费”可能是无法忍受的(虽然我觉得这里并不会有什么性能问题)。

此外您是否想过,为什么MouseListener和MouseMotionListener会是两个“事件组”而不合并为同一个呢?据说也是性能方面的缘故,因为MouseMotionListener中的事件都是“连续触发”的,换句话说,它们执行事件处理器的密度很高,如果将它和MouseListener合并,那么一个如mouseClicked这样的“普通型”事件处理器,也会让mouseMoved这样的“密集型”事件执行无谓的方法。由于执行密度很高,可能对于性能的影响就比较可观了。

可能您会说,把所有的事件处理逻辑实现在一个XxxAdaptor或是XxxListener中不就可以了吗?不过这就要求多个不同事件的处理器必须在同一段代码中添加,实在不够自由——这点在使用了Reactive Framework的时候体会尤甚。

不过,我认为Java事件模型最大的缺陷还是“扩展性”。Java中的事件大量依赖了接口,而在一个成熟的类库中,接口的使用应该是非常谨慎的,因为一旦发布了某个公开接口,它就不能进行任何修改,因为任何修改都会导致兼容性上的破坏,这方面在《Framework Design Guildlines》一书中进行了详细论述。试想,现在MouseListener中有5个方法,表示5个事件,那么如果我在新版本的类库中希望增加另外一个事件(如mouseDoubleClicked),那么该怎么办?似乎也只有创建新的接口。但是如果每次需要添加新的事件时都要增加新的接口,而其中仅仅是包含一个接口的话,类库中的补丁痕迹就会很重。更何况,如mouseDoubleClicked这样的事件明显也应该属于MouseListener的一部分。

.NET事件模型的遗憾

.NET事件模型没有Java中的许多缺点,事实上如果有人说.NET的设计参考了Java的缺点,那么我认为“事件模型”可能的确是其中一个。在.NET的事件模型中,事件是一等公民,每个事件都是类的独立成员;它们的事件处理器完全独立,不会相互干涉;在类库升级时如果要增加新的事件,使用最普通最自然的方式增加便是,仅此而已。

当然,.NET中的事件模型也不够完美。在我看来它的缺点在于,它虽然是对象,但还是有限制的对象。在C#中,我们无法将一个事件作为对象传递,无法使用一个抽象类对其进行统一处理(object类型自然除外),也难针对其利用“扩展方法”等常用特性。这个问题在某些情况下会限制某些开发模型,于是我们会为其增加一些“事件即对象”的机制

微软自己其实也意识到这个问题,因此在F#中进行了一些特别的处理。F#编译器会自动将.NET中的事件视为一个IEvent<THandler, TEventArgs>,定义如下:

// F#
type IDelegateEvent<'Delegate> =
  interface
    abstract this.AddHandler : 'Delegate -> unit
    abstract this.RemoveHandler : 'Delegate -> unit
end

type IEvent<'Delegate,'Args
  when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate> =
  interface
    inherit IDelegateEvent<'Delegate>
end

在F#中,一个.NET中的事件便是一个标准的对象,它弥补了C#里的缺点,于是许多做法在F#中便显得自然或直接了一些。例如,在F#中内置了响应式编程模型,可以直接使用。而对于C#来说,使用Reactive Framework相关功能时,则需要手动地将一个事件转化为IObservable对象——当然,有了一些辅助方法,这也就是一行代码的工作罢了。

总结

这篇文章中我简单介绍了.NET与Java中事件模型,并谈了谈自己的看法。总而言之,.NET的事件模型虽有遗憾,但较之Java的事件模型还是有很大优势的。即便是.NET中的事件模型,在某些人看来会成为“心智负担”,但比较之下我也不愿意让.NET或C#退回到Java的设计方式上——更何况,就这样一个简单的机制就能成为值得一提的心智负担吗?我对此持保留意见。

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

93 条回复

  1. 链接

    zhangle1987 2010-07-13 09:39:48

    我是一个大沙发

  2. halida
    72.52.94.*
    链接

    halida 2010-07-13 10:18:14

    看到上面一堆的代码,有种想写: Why C# Sucks and python Rocks 的感觉。

  3. 老赵
    admin
    链接

    老赵 2010-07-13 10:23:04

    @halida

    其实上面都是Java代码,基本没有C#的,呵呵。支持你写,我也对Python有一定了解,自觉C#很多方面和Python差距不大,所以就看你怎么写了,呵呵。

  4. 躺着读书
    116.77.211.*
    链接

    躺着读书 2010-07-13 10:35:12

    Why python Sucks and ruby Rocks

  5. 老赵
    admin
    链接

    老赵 2010-07-13 11:00:10

    @躺着读书

    同样支持啊

  6. halida
    72.52.94.*
    链接

    halida 2010-07-13 11:01:01

    还有,文章里面都是用法,是否可以补上原理?没有用过的人可以了解一下。

  7. yemg
    60.191.246.*
    链接

    yemg 2010-07-13 11:23:44

    使用Event机制设计的UI非常优雅。

  8. FunnyCake
    125.95.113.*
    链接

    FunnyCake 2010-07-13 11:47:09

    人家的时间都拿去发明轮子了,事件当然是心智负担

  9. billlo
    221.4.199.*
    链接

    billlo 2010-07-13 11:47:49

    看了老趙這個系列,才了解java一些東西.以前沒接觸過java語言

  10. yemg
    60.191.246.*
    链接

    yemg 2010-07-13 11:47:53

    回复的时候可以贴图片吗,有些东西使用图片的形式可能更准确。

  11. halida
    72.52.94.*
    链接

    halida 2010-07-13 12:44:48

    对event不是很了解(主要是自己没有在需要event的领域做过事,不敢写这个话题)

    找到一篇文章:http://www.valuedlessons.com/2008/04/events-in-python.html

    python的好处在所想即所写,需要什么,很容易就写出来一个了。

  12. halida
    72.52.94.*
    链接

    halida 2010-07-13 12:48:30

    恩,我发的这个不得了,把C#的event用python实现了,26行代码。

  13. 老赵
    admin
    链接

    老赵 2010-07-13 14:07:32

    @halida: 恩,我发的这个不得了,把C#的event用python实现了,26行代码。

    实现个event模型没什么大不了的,连Java都能很简单地实现类似的功能,比Python多的基本上都是些架子代码。这个场景体现不出Python的优势,其实对于动态语言来说,基本要体现优势还得上Meta-Programming。

  14. 老赵
    admin
    链接

    老赵 2010-07-13 14:14:33

    @yemg: 回复的时候可以贴图片吗,有些东西使用图片的形式可能更准确。

    可以的,看一下帮助吧。

  15. 老赵
    admin
    链接

    老赵 2010-07-13 14:15:58

    @halida: 还有,文章里面都是用法,是否可以补上原理?没有用过的人可以了解一下。

    这里没什么原理可谈,事件模型其实就是一套对外表现出的API样式,谈不到原理的。

  16. Cadina
    125.71.228.*
    链接

    Cadina 2010-07-13 14:41:00

    Silverlight里面的Trigger,Action,Behavior也很优雅啊,期待老赵讲一下

  17. 老赵
    admin
    链接

    老赵 2010-07-13 15:18:12

    @Cadina

    Silverlight我一窍不通的。

  18. 链接

    陈梓瀚(vczh) 2010-07-13 15:52:30

    道理很简单嘛,因为当初Java不支持泛型,因此根据Java语法的学院派风格,它是不可能实现event这种东西的。如果Java语法不是那么学院派的话,说不定他还是会做的。

  19. vczh
    124.79.173.*
    链接

    vczh 2010-07-13 21:02:33

    @mcpssx: 微软基本不用自己开发出的框架,是一件很值得大家思考的事情。 MFC、WPF、WinForm有哪一个微软正儿八经的用过了?微软自己为什么不用?

    你去看看Visual Studio,去看看SQLServer,谁没用了?Office也就是众多产品中的一款而已,开发比.net早,有历史原因的。VS和SQLServer后来都改成了.net,那还不就是因为好用吗。如今vs2010都用了WPF了,根据个人的经验,那速度还是不慢的……

  20. 老赵
    admin
    链接

    老赵 2010-07-13 21:42:06

    @vczh

    还有Expression Studio,Windows Live套件等等……其实微软开发的新工具基本都是使用.NET,我不知道为什么“微软自己都不用”这种调调还会在,难道非要把Office重写了才行?就怕估计到时候又会说“写个Windows看看”之类的话了,呵呵。

  21. mikeshi
    114.91.66.*
    链接

    mikeshi 2010-07-13 22:42:58

    @halida: 恩,我发的这个不得了,把C#的event用python实现了,26行代码。

    实现个event模型没什么大不了的,连Java都能很简单地实现类似的功能,比Python多的基本上都是些架子代码。这个场景体现不出Python的优势,其实对于动态语言来说,基本要体现优势还得上Meta-Programming。

    这个,这个……太不像老赵的风格了。你最痛恨的不就是那些和业务无关,仅仅为了满足编译器需求的架子代码吗?也强调过,虽然有些确实可以说是语法糖,但是正是因为这些语法糖,使很多用法变得更为廉价和实用了。现在怎么就成了“比Python多的基本上都是些架子代码”了,仿佛很无所谓一样。

    当然,动态语言确实在Meta-Programming上确实优势很大,用惯了SQLAlchemy再回头用Hibernate,简直像倒退了很多年一样,但是也不用贬低Python的event实现吧,呵呵

  22. Duron800
    113.44.0.*
    链接

    Duron800 2010-07-13 22:45:06

    @mcpssx: 微软基本不用自己开发出的框架,是一件很值得大家思考的事情。 MFC、WPF、WinForm有哪一个微软正儿八经的用过了?微软自己为什么不用?

    你自己不知道就别在这里丢人行不?你都不去了解一下就在那里胡诹?你自己不知道不代表就没有用过。

  23. 老赵
    admin
    链接

    老赵 2010-07-13 22:55:39

    @mikeshi: 现在怎么就成了“比Python多的基本上都是些架子代码”了,仿佛很无所谓一样。

    本来多出些架子代码就是无所谓的。

    谁说过我痛恨架子代码了啊?我支持的LINQ,Lambda表达式等等,声明式编程,哪个涉及到“去除架子代码”了亚?记得上次有哪本书说Ruby多强,比Java强多少,我还指出这个例子不妥当,因为数行数的时候把架子代码算进去了。架子代码,基本上都可以由编辑器生成的,我重视的都是编辑器没法生成的(当然这个架子代码也不能太丑)

    还有我什么时候贬低过Python的Event实现了啊?这是个有用的例子,我只是说它体现不出Python的强大而已,背后的意思是,Python强大,但是这个例子不好。我的确重视语法糖,但是Python少掉的架子代码是语法糖吗?而且,你说Python少了这些架子,对于编程思想的帮助在哪里?

    说到底你曲解我的话就不对了,包括我不喜欢架子代码等等,估计这其实是你的看法,但以为我也应该同意吧……

    PS: 你可以在这篇文章里搜索“架子”两个字,在评论里。还有文章正文的最后一段话(甚至整篇文章)也能表达我的看法,呵呵。

  24. yemg
    60.191.246.*
    链接

    yemg 2010-07-14 08:40:55

    微软有95%的C#+5%的C++实现的操作系统。

  25. 链接

    幸存者 2010-07-14 11:09:24

    基于委托的事件机制的一大优势就是比接口更松藕合,创建一个委托只要参数列表和返回值兼容就可以了,而创建一个接口的实例首先要保证某个类实现这个接口。

    其实.net中的事件说白了就是内建的更松藕合的Observer模式。

  26. 链接

    Ivony 2010-07-14 12:31:34

    @幸存者

    也不是这样,使用接口的方式,可以针对每个方法做一个实现类,一般会这样做。

    除了性能的问题外,就是语法的难受。事实上.NET的委托也可以抽象为一个接口: IDelegate { public TResult Invoke( T1, T2, ... ); }

    .NET中支持委托的语言会将继承于MulticastDelagate类型,且有Invoke方法的类型视为委托类型,而Invoke方法的签名即是委托的签名。而签名检查应该是编译器的事情。

    很明显这里的实现是基于“约定”。

  27. 链接

    幸存者 2010-07-14 13:07:46

    @Ivony

    我没太明白你的意思,针对每个方法做一个实现类不代表藕合不紧啊。例如我要为某个事件添加一个处理方法,我必须要先实现这个接口,这样就表示方法签名必须和接口保持一致。

    而委托只需要参数列表和返回值兼容就可以了,对方法名没有要求。这里说“兼容”是因为委托支持协变和逆变,这一点也是很重要的。

    当然C#中的委托可以看作是编译器的一种“约定”,不过其实运行时也提供了一部分支持,例如 Invoke, BeginInvoke 之类的方法就是运行时直接提供的。

  28. 老赵
    admin
    链接

    老赵 2010-07-14 13:18:49

    我注意到一点,你总是强调你对WPF,silverlinght不了解,但是老赵你肯定了解WinForm吧?

    这就是连续性方面的问题了。我对WinForm也几乎不了解,一个程序都没写过,只会拖控件,连如何布局都不会,我做的最多的还是ASP.NET方面的。

    Windows Live photo, mail、movie maker是用.net 3.5写的?

    我现在只装了Writer和Mail,都是.NET写的,clrver -all一下就可以看出来当前哪个进程用了什么CLR版本,比如我现在机器上(Expression的几个是特地打开的):

    3428    devev.exe               v4.0.30319
    4960    devev.exe               v4.0.30319
    5932    wlmail.exe              v2.0.50727
    5856    WindowsLiveWriter.exe   v2.0.50727
    1752    Blend.exe               v4.0.30319
    5496    Design.exe              v4.0.30319
    5136    Encoder.exe             v4.0.30319
    5036    ExpressionWeb.exe       v4.0.30319
    

    Expression本来就是用来表示WPF效果,自然不可能不用.net。

    Expression Studio包含很多东西了,比如Design,Web,Encoder之类的,它们的工作都和.NET无关,而且以前的微软这方面工具也都不是.NET的,因此可以说这些都是重写的新工具。而且,即便是Blend和Silverlight相关,它也不一定需要基于.NET开发,例如以前的Visual Studio不是.NET写的,不也用来开发.NET程序了吗?

    WPF、silverlinght其实现在学习的人并不多,这说明市场并没有这种程序的迫切需求。其实以后大部分可能会用html5,而性能要求高的大型程序就是C++了

    我忽然意识到现在都是在谈桌面应用。说到html 5的话,那就离不开服务器后端,这也是.NET的重要领域了。

  29. 链接

    陈梓瀚(vczh) 2010-07-15 14:36:20

    mcpssx这个论调就跟某些人自己控制不了C++就批评他复杂一样,毫无区别。学一个api很难吗?你觉得会了WinForm之后学WPF觉得太难,那不是你自己烂是什么。要是你觉得WPF容易但是又觉得太麻烦,以至于你最后WPF用的不好导致问题那么多(你看人家Expression Studio用WPF用得多好,也没见出了什么性能问题,我就用过它),那不是你学习态度不好是什么。lamp跟微软那套东西就有本质区别了?这不就是迷信吗?

    我倒是觉得java的那些个语法看起来很难受导致我不想去接近那套东西呢,虽然这是我的个人问题,不过话说回来现在电脑硬件这么强大,那点破性能的损失用我自己的功力来弥补就好了,.net的类库在我用起来(我经常开发WinForm程序,在C#上实现各种小型的编译器和虚拟机),从来就没有成为瓶颈过。

    你要是说一个SB用linux会比用windows安全,那也只能说他懂得知识太少碰不到不安全的地方。你要是说一个高手用linux会比用windows安全,那多半是他的学习态度有问题造成的。

  30. 链接

    陈梓瀚(vczh) 2010-07-15 14:37:33

    mcpssx如果你觉得学习新的东西一点都不爽,那就没什么话好说了。lamp的api是变得慢,那你尽管去用好了,也跟我没关系。

  31. yemg
    60.191.246.*
    链接

    yemg 2010-07-15 16:00:44

    @mcpssx

    美国国家广播公司(NBC)在直播2008北京奥运的时候选择的就是Smoothing Streaming,我想作为NBC这样的大公司在选择奥运直播技术的时候不会随随便便做选择,Smoothing Streaming作为视屏播放有它的优势和长处存在NBC才选择它,我并不认为微软的技术都一无是处。

  32. 链接

    陈梓瀚(vczh) 2010-07-15 16:39:31

    @mcpssx

    这个我C++用的怎么样你去点我名字去看我的博客就知道了,不需要你来想象。那作为一个程序员,要求自己必须学习知识,你不能说是不对的把。反而你给理由自己说不需要持续学习,我认为才是不对的。话说回来,我们这里讨论的是.net的问题,用户才不管你那玩意儿是java还是.net呢,管得是你的功力好不好,最终能不能把你手上的语言也好类库也好给用好了,给出一个好的程序出来。因此这里不适合用“技术思维”来反驳“用户”观点。

    有意义的事情是很难衡量的,为啥学ngix就比学winform强呢?这是毫无道理的。难道GUI就不需要高手去做吗?用户看到的可是GUI而不是你背后用了什么B+树的算法,用户的观点就是你慢一点我可以忍GUI不能卡,那归根结底这根类库的性能的关系就不大了,变成你能不能处理好GUI的事情了(那些在WinForm上自动生成一千多个Label然后就怪.net性能不好的人我也不知道这是怎么想的,我前几天还google到了这贴子)。当然性能我不否认他是重要的,不过这根你用java也好用.net也好毫无关系,算法不好,怪谁呢?那为什么那么多人用Visual Studio怪他界面慢,而不赞扬他C#的编译器快呢?话说回来C#的编译器还真是比得上当年Delphi的编译速度的,那么强大的技术,被Visual Studio不能运行在烂PC上(编译器还能高速运行在烂PC上的)不就掩盖掉了吗?究竟是谁在用技术的观点来看问题呢。

    要求工具好到你可以不需要学习就升级那是毫无道理的,那为啥有了DOS统治了PC好几年之后,Macintosh和Windows和Ubuntu会大行其道,难道不是完全改变了观念让你去学习你才能跟得上世界的步伐吗?完全是因为懒嘛,没啥好说的。

    学习是义务,不管你觉得啥必须学有啥不必须学,你靠API啥都干的出来,就是开发效率慢。显然自己开发、或者学习别人开发出来的、可以在你熟练掌握之后提高开发效率的工具是必需的。而且工具不需要给那些只会点皮毛的人用得爽。

  33. 链接

    陈梓瀚(vczh) 2010-07-15 16:40:19

    我就担心,有的人花了大量时间,只是学会了用win32, mfc, winform, wpf四种方法画出一个窗口来。

    具体到这个问题,只能怪那个人智商太低,怪不了微软

  34. 老赵
    admin
    链接

    老赵 2010-07-15 16:40:25

    @mcpssx: 什么直到今天博客园的头条还在从WPF基础讲起呢?现在silverlight都到4.0了吧?博客园每天都有一种hello、world的新写法。

    有些话我一直懒得说,但是你一直重复,那么我也就说了吧。

    如果你真关注博客园的话,你就会知道初学者们很多,他们只能从新东西学起,于是可以兴冲冲地写出文章来,他们的文章内容都是一样的,不是所谓“Hello World”的新写法,都是同一种写法。这个状态在任何技术社区都一样,你去搜索一个话题,都有无数初学者反复写反复问,这和技术本身是什么样的无关。

  35. 链接

    陈梓瀚(vczh) 2010-07-15 17:37:30

    @mcpssx

    当然事实上来说,C#编译器速度快完全是因为C#语法设计得好,而不是因为它是C++写的。你对比一下C++写的C++编译器……

    更好的工具,总是会让我们在【测试】上、【维护】上以及【开发】上达到一个更高的效率层次的,那你说值不值得花时间去看呢?至于说qt和WinForm的问题,你要是从WinForm的接口上看那完全是可以无缝插入动画什么的的,至于为什么不那么做,显然是因为WPF这一套新的东西有完全新的UI Automation Interface支持(这个对盲人和残疾人,和测试都十分有用,但是WinForm的控件分类和概念都不合适),有一套新的描述(便于UX跟程序猿分离,这个已经在我们公司里面实践过了,完全可行),等等。对于开发人员来说,为了让你的程序更加可以测试,更加可以让UX和代码分离,因此修改了开发工具(VisualStudio里面),完全是说的过去的。那你想享受这些待遇是不是也稍微学习一下就行呢?WPF到WinForm说到底也就是函数名变了一下,大部分的用法还都是差不多的(除了template和动画),如果你纯代码创建他们的话基本不会感觉到有什么区别。所以我不觉得WinForm到WPF会有多么不可逾越的鸿沟。相反qt无缝插入之后会不会受到局限性我就不知道了,因为我没碰过。

  36. 老赵
    admin
    链接

    老赵 2010-07-15 17:44:25

    @陈梓瀚(vczh): 当然事实上来说,C#编译器速度快完全是因为C#语法设计得好,而不是因为它是C++写的。你对比一下C++写的C++编译器……

    当然客观地说,C#编译器做的事情比C++要少,例如很多事情都交给JIT去做了,呵呵。

  37. vczh
    58.38.53.*
    链接

    vczh 2010-07-15 19:27:29

    我一直没办法在你这里用windows live登陆,修一下。

  38. 为了梦想
    123.134.4.*
    链接

    为了梦想 2010-07-15 20:42:47

    看评论比看文章学东西多,我只是个看评论的

  39. 老赵
    admin
    链接

    老赵 2010-07-15 21:04:55

    @vczh

    什么环境?什么错误?其他登陆方式可以吗?

  40. 链接

    陈梓瀚(vczh) 2010-07-16 11:43:37

    @yemg

    这个问题嘛,推倒重来也不是不行,你看VS2010不就重做成了WPF了吗。

    @mcpssx

    Qt不是不好,但是开发复杂界面的时候没有GC实在是受不了啊(你知道Control.Tag+GC是多么的重要,而且C++没有最终根类,因此Qt没办法有这个特性),所以这就是为什么我喜欢用C# + Managed C++ + Native C++一起开发的原因了。但是开发逻辑(就算是编译器)部分有没有GC都无所谓,因为一切的数据结构只有到了GUI之后,才会变得错综复杂起来。而且我也开发过虽然功能不是很强大,但至少也能用得GUI Framework,有API封装版本,也有全盘基于OpenGL重绘的版本,最后还是因为C#的语法更加适合写GUI而从C++做GUI转到C#做GUI了。

    @老赵

    我用的是Vista(64) + IE7,我没有其他帐号,不过看样子其他帐号是可以的,因为Windows Live不是登陆不了,而是打开那个登录网页的时候连输入的文本框都没显示出来。

  41. 链接

    陈梓瀚(vczh) 2010-07-16 15:22:10

    @mcpssx

    延续性显然不是问题,现在VB6和VC6和.net 1.1仍然可以开发服务器,调用API,写GUI,只要你愿意用就行了。要是是因为你自己不愿意用,怎么能怪软件的延续性呢?Vista刚发行的时候,还得为VB6打补丁呢。

  42. 链接

    陈梓瀚(vczh) 2010-07-16 15:26:28

    @mcpxxs

    退一步讲,微软对于商业软件的【任何一个版本】的维护政策【一般】都是10年,这个不够吗?

    换句话说,如果你调用的每一个API都是按照正确的方法来进行,那哪怕过了10年程序还都是好用的。一般来说操作系统带来的兼容性问题都是你开发软件的时候依赖了Bug导致的,我几乎没有见到过哪个API对于【正确的使用方法】有breaking change。而且PE也没改,浏览器也是向下兼容的,IIS也是(Apache更是),那哪来的延续性呢,显然只能因为新的程序猿没学过太旧的工具吗,你可以让他们学,也可以招那些学过的,这个随你。

  43. 链接

    陈梓瀚(vczh) 2010-07-16 17:17:02

    @mcpssx

    因为我相信大公司维护工具比我维护自己代码来的更可靠,所以我会持续更新最新版——如果他真的有breaking change了,那我一定会改变自己的代码的,因为那显然是开发的更好的方法。因此对于那些懒得改代码的人,显然没人阻止他非得升级不可,因此“没有延续性”也就无从谈起了。

    就如同VC6来讲,VC6的延续性真是无可匹敌啊,就算微软不干了,社会上还有一大堆的人在研究如何让VC6编译出来的程序可以运行在最新版的Windows上,虽然兼容性大部分还是微软负责的,而且跟之前的讨论一样,发生不兼容,要么就是用户的缺省权限降低了,要么就是软件依赖了Bug,总之很少是操作系统自身的错误。我认为现在还坚持用VC6不肯放弃的公司是在自取灭亡——如果他开发的东西是运行在PC上面的。

    但是版本升级跟延续性那完全是两回事。就如同C#,你从2.0升级到3.5基本没有开发和部署代价,那死抱着2.0不放跟延续性是完全没有关系的——只能说那是你自己的决定。你说C#的生命力长吗?那1.1的生命力不长能说明C#延续性不好吗?

    不要混淆视听。

  44. 链接

    陈梓瀚(vczh) 2010-07-16 17:18:15

    @mcpssx

    至于我为什么提到VC6和VB6,那是因为这两款软件可以视为“绝版”了。

  45. 链接

    陈梓瀚(vczh) 2010-07-16 17:47:49

    @mcpssx

    html这个就很纠结了,很多人抱怨IE6不够标准以至于他们要专门为IE6写代码,然后IE7变得更加标准了,让原先给IE6写的代码就不管用了,那你说IE7是应该变标准呢还是保持原状呢?(前提:IE6那会儿标准不成熟,基本不能责怪IE6干嘛干嘛,就如同VC6不标准一样,VC6比标准还来得早)

    我说的不是自己的代码,我们公司的代码也一样,以前用managed C++写了一个超大的程序,于是换成了最新的C++/CLI,语法都变了,那还不是得写。谁说劳动不算钱,但是你要看到你多年以后的【劳动总和】,而不能看你【当前项目的劳动】。我想程序猿不考虑一下以后别的程序猿维护的成本也是不负责任的。

    所以你那两个理由完全不是理由。至于说“本来不用做这么大的改变”,那仅仅是在你项目的角度上出发,而不是所有使用该工具的人的角度上出发的。难道犯了错误就一定要在无穷多的后续版本上保持这个错误吗(参考Unix痛恨者手册)?

    当然语法是一个问题,语言大幅度修改语法的情况是很少见的,目前只有在C++/CLI和python 3000上看到。但是错误嘛,无论你是不是依赖了这个错误,那既然你换到了新版本,你肯定要检查一下你以前所依赖的错误是不是还在。如果你没做这个打算,那就证明你当时决定依赖这个错误的做法就是不正确的。譬如说Windows的某些很旧的版本,free掉的指针还是能用的,你就不能做这个假设说,后续的所有版本,free掉的指针还能用。对于Windows来说,他完全没有责任保证你free掉的指针的行为,显然是程序员应该保证自己不要用free掉的指针。那因此造成的不兼容,你怪操作系统,还是怪开发软件的人啊?用户显然会怪操作系统,因此Windows为了让那个程序可以运行,为它保留了一份旧的内核代码以遍模拟这个bug,然后对新的软件严格要求。话扯远了。

    团队才是衡量成本的最小单位,而不是一个两个会跳槽的人。

  46. 链接

    陈梓瀚(vczh) 2010-07-16 17:50:40

    @mcpssx

    而且具体到managed C++的那个问题,显然managed C++的语法设计的不是很成熟,所以下一个版本重新打造也就成为了必然。但是作为一个程序员,你决定要把你的代码建立在一个还不成熟的语言上面,显然是你自己的责任了,导致后面要重写。当然有时候也是迫于其他原因才让你做这个决定的,因此这个时候就要给未来留出时间以便处理这种问题。那你说为什么不用一个成熟的语言呢——原因只有一个,这个项目不适合它。

  47. tang
    119.19.6.*
    链接

    tang 2010-11-17 14:30:39

    看到老程序员们争论这个问题,小弟觉得没必要,你在java领域当然说java好,在.net领域说.net领域好,我认为java的设计思想好,mcpssx说java比.net快,这不对吧,尤其是.net2.0后,.net的出的新东西应该领先于java,我觉得java的程序员一开始就是有色眼镜看微软的东西,说winform或wpf没vb快,没vb感觉好,这些应该不是老程序员说的话吧。.net开源资源确实不多,微软产品自己能选择不多,这当然是不爽的事,mysql收费了,jvm好像也出商业版本了,替java可惜!

  48. RobinHan
    124.42.38.*
    链接

    RobinHan 2013-06-03 17:56:26

    clr via c# 里对event 有详细的论述哦,事件只是由编译器生成一个属性而以哦, 所谓的+= new Event(), 也只是调用了Delegate.Combine 合并成一个新的delegate 实例哦, 所以event 在c#只是操作符而不是类型. 这一篇感觉老赵讲的有点乱, 不知道想说明重点是什么

  49. 链接

    Rick 2013-07-16 13:13:33

    我是来看评论的

已自动隐藏某些不合适的评论内容(主题无关,争吵谩骂,装疯卖傻等等),如需阅读,请准备好眼药水并点此登陆后查看(如登陆后仍无法浏览请留言告知)。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我