编程
标题 MSDN 访谈录之C#编程一 rainbow(翻译)关键字 C#,msdn出处 http://www.msdn.com
MSDN 访谈录(MSDN Show)
C#编程
C#是一种令人耳目一新且为之一振的编程语言,它设计给C++程序员带来快速的开发能力,而又不牺牲C和 C++所特有的功能和控制。
在今天的这一期里,我们将要和Anders Hejlsberg交谈,他是微软一位资深的工程师,一直帮助设计、开发和实现该语言,并发挥其在未来.NET平台中的作用。我们还要和Jeffrey Richter(著名的编程作家和咨询专家)交谈,他从事C#的工作已经一年有余了。
介绍
Robert Hess,微软产品经理和“Show”节目主持人。
ROBERT HESS: 让我们继续关注理解.NET体系(Architecture)。我们今天将关注新的C#(念“C Sharp”而不是“C Pound”!)编程语言。首先看看MSDN 消息更新栏目。
MSDN 消息更新
由技术编辑Erica Wiechers主持
(略去与C#无关的谈话)
技术闲聊(TECHNO BABBLE )
Robert Hess和资深工程师Anders Hejlsberg会面,要讨论…???
ROBERT HESS: 欢迎回到这个栏目。好了,就象任何一个要在其上面开发软件的平台,为了使这些应用软件能真正地运行起来,所需要的一个主要东西就是一种编程语言。目前,.NET已经拥有了一种专门为此开发的专用语言,我们称之为C#。今天和我们在一起的是Anders Hejlsberg,他是微软一位资深的工程师,在C#语言以及.NET平台领域都扮演了一个关键的角色,在以前的“show”节目里大家都见过他。所以我邀请他到这里来,和大家一起谈论C#,谈谈它是什么,有了它程序员就可以从中得到什么好处,以及它是怎样真正地影响到应用程序的开发的。
那么,您究竟从事C#哪方面的研究工作,是从什么时候开始的?
ANDERS HEJLSBERG: 在最近大概两年半的时间里,我们一直在从事C#的研究工作。设计小组由4人组成,而且在这段时间里,我把主要的精力都放在了这上面。要知道,对于一种新的编程语言,我们有许多事情要去做。我想首先也许就是为程序员提供方便,使程序员开发出更多的产品就是最终目标。如今,虽然在产品的收益方面仅仅只是初具规模,但可以说,我们的目标,在某种意义上,不但要使C#具有C++强大的功能和出色的表现,而且还要使其具备简单易用以及RAD(Rapid Application Development,快速的应用程序开发)语言的生产率。
我们已经做了一些工作,例如,涉及到程序员如何利用更好的工具编写组件的范畴。如果你看看我们是怎样写应用程序的,应该是曾经怎样写应用程序的,如果回顾过去,也就是说5年或10年以前,应用程序就是这样铁板一块地被创建的,它和操作系统的唯一交互,你知道,就是进行文件的i/o操作,而且无论如何操作系统都会载入应用程序,接着用户就与其交互,最后退出。看看现在我们是如何创建internet应用程序的,相比起来简直是天壤之别。应用程序不再是铁板一块了,而是由一系列更小的组件构成,它们分别栖息于不同的环境。例如,你可能拥有类似存储过程(stored procedures)和SQL Server那样的组件,也可能拥有栖息于浏览器中的控件,或者是存在于ASP网页中的代码。商业对象生存于中间层,调用整个集合的组件就等于调用该应用程序。于是为了使……
ROBERT HESS: 而当时您明白其中的每一个组件都比5或10年前的一个应用程序更加复杂。
ANDERS HEJLSBERG: 噢,绝对,绝对。同样,为了减少创建组件的复杂性,不象那种大块头程序,每当必须创建其中的一个组件时,就不必另起炉灶,而应该尽量继承一些早已存在于这些专门的栖息环境(hosting environment)中的东西。如果要写浏览器中的一个控件,就要继承一个基控件;如果要写中间层的一个商业对象,就要继承某些商业对象类;而要想公开属性、方法和事件等等,就要说明它们是如何通过把属性与组件联系一起,以便与栖息环境相结合。而且还要能够为这些组件撰写随组件一起发布的文档。
ROBERT HESS: 所有的这些只是标准的面向对象的编程,Smalltalk 拥有此特性的时间似乎已经不短了,并且……
ANDERS HEJLSBERG: 嗯,绝对如此,现在并不是不能做这样的事。但如果注意一下这种今天已经得到了广泛应用的编程语言,它们实际上并不真正支持面向组件的概念。如果你当初同意我们什么时候谈论组件,那么认为它们具有属性、方法和事件在当今是极其平常的。但如果注意一下C++,就会发现它仅仅提到“方法”这个概念,没有属性,也没有事件。现在,你可以利用命名模式来仿真它们,也就是说,对于一个属性,可以用一个get color和一个set color的方法来取代一个color属性;而要代替类中作为第一个类成员的事件,你拥有的用于接收事件的接口就应该被实现,为了这样,你就必须处理一些琐碎的事……
ROBERT HESS:嗯,部分原因是由于C++是基于C的,它只是象预处理程那样,又由于C本来就不支持,C++也不支持……
ANDERS HEJLSBERG: 是的,实际上我多少认为,你所看到的就是从C到C++再到C#的发展过程。从C到C++,面向对象编程的概念被加进去了。如果你经历了从C++到C#,那么我会说,面向组件编程的概念也已经被加进去了,而它们之间真的存在着某些相似的地方。就象可以用C代替C++进行面向对象的编程,你也可以用C++代替C#进行面向组件的编程,只不过是更困难而已。用C来进行面向对象的编程是极其困难的,你必须手工地布置V表(虚拟函数表),并且还要处理所有琐碎的事情。用C++写组件也确实可行,但必须要为属性手工地设置命名模式(naming patterns),必须实现事件同步(event syncs),必须具有外部的IDL文件,在文件中可以对栖息属性(hosting attributes)进行描述,必须具有外部的文档文件,等等。我们只真正采纳了其次一个合理的步骤,它反映了人们是如何编写应用程序并把其整合到语言中的
ROBERT HESS: 那么,最初的一些目标是什么?仅出自内心的看法,当您第一次着手这个项目时,您要解决的问题和要确定的这种新语言的方向是什么?
ANDERS HEJLSBERG: 嗯,我认为正如您所说,面向组件只是一方面。我想另一个关键的因素就是简单化。使编写应用程序更加简单化,不让程序员做一些琐碎的事,机器可以代你做。大量的简化取决于.NET runtime本身,但也取决于语言。基本上,最终我们所做的,就是让你把更多的时间、更多的精力放在算法上,而让系统去做一些琐碎的事。我认为,许多其它非常关键的事情比较现实,我总不能吩咐人们把他们现有的代码通通扔掉吧。我们必须找到权衡的方法,并不仅仅是你的编程技巧,而且还包括你以前编写的、早已存在的代码。因此在C#里,以权衡你技巧的名义,我们努力坚持在与C++的基础语法最接近、最真实的地方。所以用了C#,C++程序员会立即觉得很眼熟、很亲切。
ROBERT HESS: 您的所做的一切应当以C语言为基础,是否就是当初的思路之一?或者您是否原来就认为,让我们应与过去彻底决裂,再开始设计一种全新的语言?
ANDERS HEJLSBERG: 嗯,我想这种语言应该以一种崭新的面貌出现,可是我们明白,必须让C和C++程序员熟悉这种语言。当然那就意味着在某种程度上,我们必须把语句结构从弯曲的大括号变换成其它一些东西。我们已经打下了一些基础,但仍然存在着其它某些关键的规则,譬如允许写健壮的软件,这就意味着象垃圾回收(garbage collection)、异常处理、类型安全这样的功能,根本地改变了设计该语言的思路,非常难于上手,以后也不容易扩展。我的意思是说,在C++中,C++语言拥有的一个强大功能之一,但有时也同样是难点之一,事实上您知道,就是没有类型安全。如果你了解清楚自己要做什么,就会从中获取巨大的力量,否则,只是自找苦吃。在C++中,获得一个虚悬指针(dangling pointer)易如反掌。同样,覆盖掉一个数组的尾部,或者拥有一个未初始化的变量等等,也是极其容易事情。而我们需要解决这些难题。我认为,我们不能只从 C++着手并扩展它。而真的必须以退为进,以C++的灵魂设计出新的方案,而这些我们已经差不多完成了。
ROBERT HESS: 那么其它语言呢?您注意到这些语言在做了什么吗?是否它们就是Pascal 或 Modular 2 或 FORTH,您从中得到什么借鉴?
ANDERS HEJLSBERG: 绝对!噢,我们考虑到,嗯,我的意思是说,我本人出身于深厚的Pascal背景,所以,自然要考虑到Pascal, Modula, Oberon, 要考虑到Smalltalk,Java,C++以及所有的语言。要知道,今天它们能生存下来并得到了应用,且或多或少地传播开了。
ROBERT HESS: 您觉得这些语言的哪些功能比C和C++表现得更出色?而您就可在新的语言中引进这些功能?
ANDERS HEJLSBERG: 嗯,我认为有一件事可以说明,我总是喜欢Smalltalk,就是因为在该语言中,任何东西都是对象。这使程序得到了大大的简化,因为无论拥有什么样的数据片,都可以把它当作一个对象从A点搬到B点。一般来说,任何东西都可以对其进行操作。可以把它当作对象类型,放在容器中。在Smalltalk实际的实现过程中,如果这样做的话,程序性能的额外负担(overhead)就会大大加重。例如,在Smalltalk中,当运算float数字时,每生成一个新的数字,如当1.0和2.0加到一起时,就要分配一个含有3.0值的新对象。而这样做,代价当然是非常昂贵的。如今在C#中,我们已经进行了一些革新工作,使你获得了同一样的利益,而却没有额外负担。只要把float当成float,或者是double就把它当成double使用,就没有什么代价。但如果把它们视为对象(也仅当这样做时),就得给它们分配堆(heap)。因此,就形成了样相当完美的统一体,既能给您大量的好处,而又没有程序性能的额外负担。
ROBERT HESS:C#生成的最终结果的某些结构到底如何?您得到了一个C#程序的文本文件并且编译它,那么编译器本身存在着些什么问题,如何设计这些方案以便在使用时更具效率,而这种优化其它语言有可能已经做过,而甚至最终还要生成二进可执行文件吗?
ANDERS HEJLSBERG:嗯,我们已经做了一些涉及到如何编码的工作。假如你是一个C++程序员,当然熟悉怎么做,在C++中声明和实现是分开的。所以所有声明都放在H文件里,接着在另一些模块中把它包含进去(# include),然后再在CPP文件中写出实现程序。在C#中,把它们都写在同一个地方。这样,可在那里写出声明接着又立即写出实现代码。
ROBERT HESS:假如您必须在另外一些文件中采用在main文件中声明的某些值,那又怎么办?
ANDERS HEJLSBERG:那么会出现什么情况呢?当编译时,实际生成的代码或重新生成的输出文件都含有两种代码:元数据(metadata),符号表(symbol tables)或其它相关的符号信息(symbolic information),而不是仅生成只含有可执行代码的X86机器码。在某种意义上,这些代码变成了自我描述。所以当想从一个代码片使用另一代码片时,只要引用它们便可,而这些代码的自我描述足以让人们知道在那里有什么类,类拥有什么成员,可以调用什么方法,属性是什么以及类型名是什么,等等。
ROBERT HESS:那么,是不是象您所指的.OBJ文件或.EXE文件,抑或……
ANDERS HEJLSBERG:嗯,您说的很对,我们在.NET中使用的格式就是PE格式,故可以指向另外的EXE或DLL。我们现在调用这些汇编程序,并基本上用这种语言大量地描述这些高级DLL,它们不仅含有代码,也含有这样的信息:说明什么在代码中,以及这些代码真正地引用了其它什么样的汇编程序。
ROBERT HESS:您所说的代码是指二进制代码或可执行代码。
ANDERS HEJLSBERG:嗯,实际上,我们并不直接生成可执行的X86机器码,而是生成MSIL,也就是中间语言,它由.NET定义,并由JIT(实时编译器)编译。
ROBERT HESS: Ok,这样看来,您拥有了一个可执行文件,其本身与中间语言以及元数据相关联,而如果我想要在其中一个应用程序里使用它,我只要指向它并说道,嘿,我要借用这些类,借用这些对象,并在这样的程序中使用它。这使我想起了许多人曾经提过的一个问题,涉及到中间语言存在着潜在的漏洞,有些人可能会攫取这种文件并对其进行反编译,然后再恢复成当初的源代码。因此,并非所有的智能特性(intellectual property)都有利于开发者。这方面还有什么问题?
ANDERS HEJLSBERG:嗯,首先,您现在实际上可以用DLL进行处理。这可能有点难,但您可以采用包含X86码的一个DLL,然后至少把它反编译成汇编程序。您可做同样的……
ROBERT HESS:在我的Apple II上,我一直都是这样做的。
ANDERS HEJLSBERG: 确实如此,我对此感到惭愧。但是运用.NET DLL并把其反编译成MSIL,也可以做相同的工作。它们并不能直接地被反编译成C#,尽管您也有可能蒙对,但太难了。不同的地方在于,有着非常多的符号信息(symbolic information)关联到由C#生成的代码,以及MSIL,对不起,是.NET汇编程序。例如,你可以从代码中得知,什么类在这里,它们的成员是什么,等等。这是一个需要解决的棘手问题,因为让代码自我描述(self describing)的好处多多,但事实上代码对自己进行的描述,也同样使反编译工具所处理的代码变得似乎容易理解了。如果我们认识到这个问题,基本上我们要做的,就是创建一个称作搅拌机(obfuscator)的东西,它会加入并搞乱代码,使代码变得几乎难于看懂,可仍然保留着原来相同的公共接口。
ROBERT HESS:是的,因为您遇到这样的难题:当采用、编写这些编译器程序时,就想让编译器理解代码(或类似的过程等),但却不想让人们在同一层次上看懂它们。
ANDERS HEJLSBERG:确实如此,确实如此。我确实想指出,对于一个小程序,实际上可以对其进行反编译,给出足够的时间和资源,你甚至可理解它在干什么。然而对于真实世界中的一个应用程序,这却是一项艰巨的任务。在现实中你最好运行这个应用程序,理解它在干什么,然后写出它的一个copy。你会很快达到这个水平的。
ROBERT HESS:或许写出一个更牛的程序,因为您是一个更牛的程序员,对吗?为了断定我们的观众是否想要着手实现下一个C#项目,他们需要去理解有关C#的一些什么问题?
ANDERS HEJLSBERG:嗯,我想首先你必须考虑到自己的基础。如果你有现成的代码体,让我们假定它是用C++写成的吧,也许把这些代码移植到.NET framework的最佳途径就是使用Managed C++,该C++编译器随.NET一起发布。然而,如果你着眼于编写新的代码,也就是写新模块、更大的模块,加入到一个应用程序或一个完全了解的应用程序中,而且你精通C++,那么我建议考虑C#。
ROBERT HESS:因此,我们没有必要说,每个人都必须用C#重写他们的应用程序。我们在说,人们必须了解他们目前所从事的工程的类型,是否是一个现成的项目、陈旧代码,并且有时还要用C#写一些组件,莫非您可以交替地使用C#和C++?
ANDERS HEJLSBERG:噢,绝对。首先,如果你拥有现成的代码,假定这些代码是由Windows平台所支持的任何一种语言写成的,则把它们编译成COM组件或DLL,就会获得与这些代码很强的交互操作能力(interoperability)。如果要写专门用于.NET framework的代码,用于.NET framework的新代码,当然要用.NET framework所支持的任何语言写。我们计划在Visual Studio .NET中发布四种语言:C#、 C++、 Visual Basic 和 Jscript。可是为了与产业界和学术界合作,我认为,最新的统计可能不是很准确,但我想总共大约17种不同的语言现在都瞄向了这一个平台,其范围一直从APL到Cobol。
ROBERT HESS:那么象Fortran又怎么样呢?
ANDERS HEJLSBERG:我相信相关的工作正在进行中,可我不能准确地知道到底谁正在设计Fortran编译器。但关键的是,实际上我们已经做了多次示范了,你可以在C#中写一个基类,并在C++中继承它,然后再用VB程序创建它的一个实体。在不同的语言之间进行的互用操作是无缝的。我想正是这些性能,使.NET framework甩开产业界中其它竞争对手的产品。(有兴趣的读者可以到http://www.lahey.com/net_down.htm去下载Lahey/Fujitsu Fortran for .NET Technology Preview 1,译注)
ROBERT HESS:而且它采用并允许在基础层次上进行多语言的互用操作。
ANDERS HEJLSBERG:是的,很准确。不过是位于一个很高的层次。您可能会争辩:现在的语言可以进行互用操作,但只能位于很低的层次,例如,DLL的入口点、具有指针在其中的结构,等等。而我们正在谈论到更高的语义层次,是位于面向对象的层次,具有类和接口等等。