为什么选择 .NET?






3.35/5 (89投票s)
2004年5月20日
21分钟阅读

528489
在本文中,我将阐述为什么像您这样的开发者应该关注 .NET,即使您目前不打算转向 .NET。
为什么选择 .NET?
在本文中,我将阐述为什么像您这样的开发者应该关注 .NET,即使您目前不打算转向 .NET。当然,围绕 .NET 有很多市场营销的浮夸之词,但让我们跳过这些浮夸,来谈谈技术方面。具体来说,我将讨论为什么 .NET 对开发者很重要。
不管你喜不喜欢,.NET 正在到来
.NET 是未来开发的方向,不仅适用于 Windows 平台,也适用于其他操作系统。如果你现在不打算转向 .NET,至少应该及时了解它的最新动态,并定期重新评估它,以确定何时开始转向它。
.NET 正在到来。忽视这个事实并不能减缓或阻止它。那些不转向它的人将成为恐龙。与其灭绝,不如提前规划迁移。
如果你现在就开始评估 .NET 并计划平稳及时的迁移,你将受益匪浅。然而,如果你等待太久,未来是相当可预测的,就像我们都知道的那些拒绝承认 Windows 已经到来的 DOS 开发者一样,很容易看到其结局。
为什么不是 Java?
本文并非对 Java 的抨击或攻击。总的来说,本文面向的是 Win32 开发者,而非 Java 开发者。但问题仍然存在:“为什么是 .NET 而不是 Java?”。我只在本文中总结我的观点。在未来的另一篇文章中,我将比较 .NET 和 Java 并预测未来。
Java 是一个成熟的平台,有其自身的优点。本文仅阐述我认为 .NET 很重要的理由。我只在存在我个人认为特别重要的对比或特定差异时才提及 Java 平台。
.NET 在许多方面优于 Java 平台,而 Java 在其他方面表现更优。然而,关键的区别在于 .NET 将在未来轻松弥合差距,而 Java 若不进行重大重新设计,变成与现在截然不同的东西,就无法弥合这些差距。
.NET 相较于 Java 的一些优势在于
- Java 不仅仅是一个平台,还是一种语言。.NET 是与语言无关的。采用 .NET 不会强迫您采用单一或特定的语言。.NET 甚至可以支持 Java 语言,而且 J# 与 Java 非常接近。
- 语言互操作性。
- .NET 可以与现有的 Win32 代码共存甚至整合。
- 从 Win32 转向 Java 是一次彻底的范式转变。对于 Win32 开发者来说,转向 .NET 是一条更自然的道路。
.NET 的原因
“它规模庞大,而且是微软的产品。”如果我每听到一次这句话就得到一欧元的话……虽然这可能是真的,但这并不是转向 .NET 的有效理由。你可以在一架大型喷气式飞机上漆上微软的字样。但这并不意味着人们会踊跃报名乘坐这趟航班。事实上,你应该对 .NET 持怀疑态度,但让我们来探讨一些 .NET 对你来说重要的具体原因。
虽然这不是一个技术原因,但这仍然是学习 .NET 的一个理由。微软在 .NET 的市场营销上投入了**大量**资金,并吸引公司转向它。许多负责此类决策的经理并不精通技术,但他们信任微软。他们将纯粹基于微软告诉他们这是唯一未来以及看到竞争对手转向 .NET 的原因,而转向 .NET。
当公司转型时,自然需要开发人员。现在学习 .NET 可以确保您未来作为一名有就业能力的开发人员,并比那些等到最后一刻才学习的开发人员获得先机和更多经验。
纯代码
除非你一直在洞穴里开发,否则你很可能听说过“安全代码”这个词。但这到底意味着什么?与其谈论安全代码,不如谈谈“纯代码”。
应用程序可以在 .NET 平台上编译和执行,但仍不是“纯” .NET 应用程序。“纯”是一个主观的术语,不一定是官方术语。我将把一个纯 .NET 应用程序定义为具有以下属性:
- 100% 安全代码
- 100% 托管代码
- 无 P/Invoke
任何 .NET 应用程序的最终目标是使用 100% 纯代码,并将所有其他代码隔离到单独的程序集中。在一个 100% .NET 的世界中,所有应用程序将只运行纯代码。只有设备驱动程序、加密、压缩和其他此类项目将作为非安全代码运行。
托管代码
托管代码是在 .NET 框架控制下执行的代码。可以由 .NET 框架管理的,是基于 IL(中间语言)的代码。非托管代码包含由汇编语言助记符或传统编译器(如 C++ 或 Delphi (.NET 版本))生成的特定于 CPU 的指令。
像 C# 和 Visual Basic.NET 这样的语言只生成托管代码。然而,Delphi,特别是 C++ 可以生成包含托管代码和非托管代码的混合应用程序。
混合模式应用程序可以与 .NET 框架集成,并允许从 Win32 更容易地分阶段迁移。混合模式程序集对于与硬件集成也是必要的。然而,由于混合模式应用程序包含特定于 CPU 和操作系统的信息,这将 .NET 应用程序绑定到特定的 CPU 和操作系统。因此,此类应用程序使用 .NET,但并非完全在 .NET 框架下运行,并且与 Mono、64 位 .NET 框架等其他 .NET 实现以及未来其他实现不兼容。
许多服务器环境都有安全限制,只允许运行纯托管代码的应用程序。非托管代码项目必须得到管理员的明确信任,并保留用于设备驱动程序等。
简而言之,如果应用程序的任何部分是非托管的,则整个应用程序都应被视为非托管的。如果某些项目(例如硬件)必须与托管包装器集成,则应创建托管包装器。所有此类项目都应创建并部署为单独的隔离程序集,以便于管理。
安全代码
安全代码是严格遵循 .NET 框架类型安全规则的代码。不安全代码是旧代码,不遵循这些规则。不安全代码允许使用指针、特定于机器的字节顺序和特定于语言的类型。不安全代码需要额外的权限才能执行。
可以使用名为 PEVerify 的工具检查程序集是否包含不安全代码。PEVerify 是 .NET 框架 SDK 的一部分。
无 P/Invoke
P/Invoke 是 Platform Invoke 的缩写,指的是无需使用 .NET FCL 即可直接调用操作系统的能力。在 Windows 中,P/Invoke 也允许调用用户或供应商的 DLL。P/Invoke 类似于 Java 中的 JNI。
使用 P/Invoke 并不会使代码不安全或非托管。然而,它确实会使应用程序依赖于特定于操作系统的项。这再次导致应用程序无法在 Mono 和其他未来的实现上运行。应避免使用 P/Invoke,尽可能改用 FCL 中的函数。
平台潜力
由于 IL 是通用的,它不绑定到任何特定的 CPU 或硬件平台。虽然 IL 目前仅支持 Windows,但其设计专门考虑了其他平台。在 Linux 上,已经有一个名为 Mono 的项目允许 IL 代码在 Linux 上运行。未来,其他平台也将实现 IL 执行。
语言中立
.NET 是语言中立的。.NET 中最常见的三种语言是 C#、Visual Basic 和 Delphi。但 .NET 也支持许多其他语言,包括 Fortran、Smalltalk 等。
但是 .NET 不仅仅是语言中立。通过其 CLR(公共语言运行时)和 CTS(公共类型系统),.NET 将所有语言整合在一起。CLR 和 CTS 允许所有语言使用其他语言生成的程序集,就像它们是由同一语言生成的一样。不再需要笨拙地转换参数类型、调用约定或命名约定。现在,C# 用户可以使用 Delphi 程序员生成的所有代码,Visual Basic 用户可以使用 C# 开发者生成的所有代码,以及任何语言组合。开发者不再被语言隔离,被迫只能通过困难而笨拙的导出进行交互。
想象一下,如果《星际迷航》中的通用翻译器今天突然问世,俄罗斯人可以直接与德国人、荷兰人、西班牙人,与任何语言的人交流。每个人都使用自己的母语,却每个人都听到自己的母语。这正是 .NET 对编程语言所做的事情。
未来会更快
这是否意味着 .NET 现在很慢,我们必须忍受,直到拥有更快的 CPU?不!
让我们退一步,看看我们今天如何构建应用程序。当我们编译源代码时,编译器会为特定类型的 CPU 生成汇编代码。对于 Win32,这可能是针对 486 CPU 的。在 486 上,代码会以最大潜力运行。然而,今天很少有人使用 486 电脑,事实上,大多数人使用的是更新了许多代的 CPU。但由于您无法预测用户会使用什么,因此您必须为尽可能低的因子进行编译。这也严重限制了 Intel、AMD 和其他 CPU 制造商,因为必须在许多代中保持向后兼容性。
对于 .NET 代码,您的源代码会被编译成 IL。然后,此 IL 可以在任何具有 .NET 框架的 CPU 或操作系统上执行。这种 IL 不仅仅是被解释,它本质上是根据平台优化的指令集按需编译的。这种按需编译器可以在未来轻松更新,以支持更新的 CPU 甚至不兼容的指令集。然后,每个独立用户都将运行其自己的优化版软件,针对他们的硬件。所有这些都无需重新编译您的代码或向用户重新分发您的应用程序。
从 16 位世界迁移到 32 位世界对于开发者来说是相当痛苦的。它不仅仅是简单地重新编译代码,因为许多底层支持架构都发生了变化。但是使用 .NET,您可以进入 64 位世界,并利用更快的处理能力,而无需重新编译、重新设计甚至重新分发您的软件。这就是我所说的升级保险!
虽然 C++ 可以针对许多平台进行编译,但这要求每个构建都针对每个平台进行构建。这是一项维护密集型任务,在许多情况下也很昂贵。跨平台 C++ 代码有很多限制,而且代码通常在不同平台之间编译不佳,而 .NET 代码始终是跨平台的。关键因素是,对于未来的平台,C++ 必须在编译器可用时重新编译,而 .NET 代码不需要任何更改或重新编译。
未来例外
使用 Visual Studio 2003 构建的 .NET 1.1 应用程序可能无法自动利用 64 位 CPU。由于许多开发人员仍在编写不安全代码并依赖 CPU 字长,Visual Studio 目前将其 IL 输出标记为 32 位标志。这将导致 64 位 .NET 在 32 位兼容模式下执行这些程序集。这将利用部分 64 位 CPU,但不是全部。
如果您的代码是安全的并且没有“位性”问题,您可以覆盖此标志,然后您的程序集应该以 64 位模式运行。支持 .NET 2.0 的下一版本 Visual Studio 计划发出一个平台中立的标志。其他 .NET 1.1 语言可能没有 Visual Studio 所使用的保守值,因此无需更改即可利用 64 位。
虽然这个限制确实不令人满意,但它不是 .NET 框架的限制,而是 Visual Studio 的设计选择。
改进的 VB
Visual Basic 多年来增加了一些“糟糕”的功能,这些功能允许甚至鼓励糟糕的编程习惯。这使得 Visual Basic 在许多圈子里名声不佳。
.NET 迫使 VB 回归到正确的开发实践领域,并将阻止其设计者将其改回原样。本文也不是对 VB 的抨击,但对于那些需要提醒的人,我有两个词要说:Option Implicit
。这个选项已经够糟糕了,但它却是项目的默认设置。VB 还有许多其他类似的缺陷,是 .NET 强制修复的。VB.NET 仍然保留这个选项以实现向后兼容性,但默认设置已更改。许多其他项已被完全消除。
现代化 C++
我意识到接下来这个话题会让我与 C++ 开发者陷入困境。但是……C++ 是一种出色的低级语言——这正是它设计的目的。但是 C++ 正是因为如此适合低级编程,所以它作为应用程序语言并不那么合适。它在最简单的任务中坚持使用指针,这本身就使其按照 .NET 的定义变得“不安全”。
因此,我们有了 C#。C# 是一种基于 C++ 的 .NET 兼容语言。C# 最终迫使 C++ 程序员放弃旧习惯,转向安全的编程实践。
那 C++ 何去何从?C++ 仍然是编写非托管程序集以进行直接硬件访问、高性能数值计算、压缩和加密的首选语言。因此,C++ 的忠实拥护者无需担心——C++ 在可预见的未来仍将存在。但随着许多同伴开发者部分或完全转向 C#,你们的队伍将会缩减。
对于应用程序、服务器、业务和通用开发,C++ 开发者应该转向 C#。虽然你可能会失去许多你在 C++ 中已经爱上的低级功能,但 C# 是一种语法基于 C++,但专为 .NET 构建的语言。一开始它可能会让你感到不适,但你会逐渐爱上它,并且不会回头。
指针受到 C++ 开发者的喜爱,就像 Basic 程序员喜爱行号一样。我当然无意将现代 C++ 开发者与 Basic 程序员相提并论,但根本性的转变是相同的。一旦你转变,你将不会怀念失去的东西,并且会因此变得更好。
更少的崩溃
在 .NET 平台上运行的代码更不容易崩溃,托管代码几乎不可能导致系统崩溃或影响其他应用程序。
这归因于两个因素
- .NET 限制了应用程序可以做什么、可以访问什么以及如何管理内存。
- .NET 强制开发者使用现代语言和现代编程实践。.NET 强制开发者放弃为 20 世纪 70 年代计算机系统设计的旧习惯和技术。
C++ 开发者也很快会回复说“现代 C++ 对 X 和 Y 有警告,或者编译器选项 Z 可以防止这种情况发生。”警告的问题在于 C++ 会发出如此多的警告,而 C++ 开发者通常无论如何都想覆盖它们,以至于每次编译时,一个 C++ 程序会发出数百甚至数千个此类警告。找到重要的警告并非一项快速或容易的任务。编译器选项也存在问题。由于 C++ 开发者通常是速度狂人,几乎所有此类安全措施都在发布版本中关闭,无论代码是否运行得足够快。由于发布代码被更广泛的用户群体使用,发布版本会遇到调试版本中从未遇到的情况,然后直接崩溃。.NET 强制这些检查始终开启,通过正确处理异常而不是仅仅损坏内存或其他来提供更好的应用程序。
揭穿神话
.NET 在许多开发者的心中引起了恐惧。其中一些恐惧是基于事实,但被误解所包围,而另一些则基于纯粹的错误信息,在某些情况下,甚至是宗教信仰。让我们用逻辑的方法来审视一些更常见的恐惧。
- .NET 有一个庞大的运行时。
.NET 有一个 20 兆字节的运行时。这对于一个普通应用程序来说太大了。
首先,它不是运行时库。.NET 框架是一个完整的平台,类似于 Win32、DOS、Unix 和 Java 都是平台。目前,.NET 运行在 Windows 之上,因此必须安装。
.NET 框架 1.1 版本的安装大小约为 20 兆字节。然而,Windows XP Service Pack 1 光盘在其安装中包含此运行时,并且许多用户已经安装了该框架。未来,.NET 框架将获得越来越广泛的接受,就像 DirectX 等其他 Microsoft 组件一样。大多数游戏都依赖 DirectX 安装,并在没有问题或对运行时抱怨的情况下进行安装。
未来版本的 Windows 操作系统将附带 .NET 框架,作为原生操作系统的一部分。
从整体来看,20 兆字节的发行版也不是非常大。大多数软件都有几兆字节甚至更大。.NET 运行时只需由那些尚未安装它的用户安装,因此是可选的。在 CD 发行版中添加 20 兆字节的安装并在需要时安装不会对部署产生负面影响。
在电子下载领域,20 兆字节更具衡量意义。然而,通过互联网进行的电子下载通常由技术娴熟的用户完成,他们可能已经安装了该框架,或者拥有 DSL 或更好的互联网连接。
20 兆字节也指的是完整的框架。当您的应用程序加载时,它不会链接到一个加载到内存中的 20 兆字节运行时,就像今天的标准 Win32 应用程序每次运行时不会加载 200 兆字节的 Windows 支持一样。
- .NET 很慢。
有些 .NET 应用程序确实运行较慢。压缩和加密例程就是一个例子,它们通常运行较慢。由于安全隐患以及需要以加密所需的方式直接操作结构,此类功能无论如何都应该使用非托管代码编写。
然而,此类应用程序在一般开发需求中只占极少数。大多数开发者要么开发服务器端对象,要么开发桌面应用程序。这些任务如果编写得当,在 Win32 中会以同样快的速度执行,甚至更快。
更快?是的,更快。这是因为 .NET 框架实现并提供了比 Win32 应用程序更多的服务,也因为 IL 代码实际的优化和执行方式。
但是我移植了我的应用程序,它慢了 100 倍!
这是一个非常常见的场景。许多应用程序在移植后,运行速度比原来的 Win32 应用程序慢 100 倍甚至更多。但我说过它们应该运行得更快,对吧?那么,为什么这么多应用程序在移植后运行得更慢呢?
答案很简单——应用程序被移植了,但设计保持不变。也就是说,执行的是直接移植,而没有使用新的开发技术。
当然有可能将 1960 年代老爷车的巨大引擎放入现代汽车中并使其运行。然而,用无铅燃料驱动它,并将其与 40 年后设计的汽车系统和车身整合,将无法产生预期的结果。在移植到 .NET 时,您需要考虑到它在几个关键领域的工作方式是不同的。
您是否必须从头开始重新设计您的应用程序?不必。但您应该审视一些关键领域,并考虑改变它们,使其在新范式下运行,从而能够正确高效地运行。
- 失去控制。
许多开发者已经非常习惯于拥有完全的控制权。这种习惯对于 C++ 开发者来说尤其如此。如果您的控制定义是直接访问内存,那么为 .NET 开发会削弱这种控制。在大多数面向对象语言中,开发者已经越来越远离直接内存访问,转向托管内存和对象接口。.NET 将这种趋势推向了新的高度,只允许托管内存和对象。
尽管一开始这可能会让开发者感到不适,因为他们可能需要改变长期养成的习惯,但这种改变是好的,甚至是必要的。
.NET 的未来
.NET 是新事物。框架的当前版本是 1.1,2.0 正在开发中,预计将在 2005 年问世。因为 .NET 是新事物,我将花一些时间讨论 .NET 的未来,这将有助于解释为什么 .NET 如此重要。
即使您现在不打算转向 .NET,将来您也会转向。未来抵制转向 .NET 的开发者和公司,将类似于今天编写 Windows 3.1 或 DOS 应用程序的开发者。.NET 正在到来——虽然您现在可能不会转向它,但您越早接受您总有一天会转向的事实,就越好。
Mono
Mono 是一个用于 Linux 的 .NET 实现,允许托管 .NET 代码在 Linux 上执行。Mono 之所以令人兴奋,因为它表明,虽然微软是 .NET 背后的推动力,但 .NET 本身可以而且将会在其他操作系统上可用。
大型机
将来,我预计 .NET 框架将可在大型机类计算机上使用。对于在大型机上投入巨资的企业来说,这将是一大步。正如 Mono 所展示的,这是完全可能实现的,只是时间问题。
服务器
未来,随着 .NET 在更多操作系统上可用,服务器将能够运行基于服务器的程序集。操作系统甚至 CPU 将不再重要,任何支持 .NET 框架的服务器都将能够运行由使用任何其他操作系统的开发者编写的程序集。
Windows
Windows 目前基于 Win32 内核。.NET 框架运行在 Win32 内核之上。然而,在未来的 Windows 版本中,这种关系将变得模糊并最终反转。这与 Windows 3.1 演变为 Win32 的方式非常相似。
未来,微软将发布一个“就是”.NET 的操作系统。驱动程序和受信任的代码仍将被允许在高层运行,以提供硬件和其他必要的支持。然而,非托管应用程序将在一个兼容性环境中运行,该环境模拟 Win32 API 并将其转换为 .NET 框架。这类似于 Windows 3.1 应用程序在 Win32 上运行的方式。
每个应用程序的最终目标是成为托管应用程序。虽然这看起来可能很牵强,但如果我们回顾历史,就会发现并非如此。在 Windows 3.1 甚至 DOS 时代,拥有所有 Win32 应用程序似乎是一个遥远的梦想。然而今天,很少有用户仍然使用 Win3.1 或真正的 DOS 应用程序(不要与 Win32 控制台应用程序混淆)。而且,很少有开发者仍然为这些环境开发代码。
再教育
.NET 确实需要一些再教育和开发者心态的改变。但当开发者从 DOS 转向像 Windows 这样的事件驱动环境时,也存在同样的改变。必须留出一些时间进行重新学习,但投入的时间会很快得到回报。
编写安全代码对开发者施加了新的限制,并需要一些再教育来学习新D技术。但这些新技术是应用程序开发者以前应该使用但没有使用或无法使用的最佳实践。.NET 有助于强制执行这些最佳实践。
摘要
很难总结整篇文章。文章本身就是一篇总结。所以,让我们来看看一些比较。
Win32 代码就像一辆 1950 年代的 Corvette。洗得干干净净,充满原始马力。你可以进去捣鼓引擎,轻松进行改装。你可以让它脱档。如果你愿意,可以在每小时 100 英里的速度下挂入一档。
.NET 是一辆 2004 年的 Corvette。仍然有很多马力,但现在您有安全带、电脑控制的引擎、安全气囊、防抱死刹车和安全玻璃。
作为古董,1950 年代的 Corvette 确实有一些魅力。但在开发软件时,我们很少有人会怀念打孔卡或 DOS 窗口。所以,这就剩下安全性和能力了。汽车当然不像软件那样经常崩溃。如果它们也那样,人类人口就会急剧下降。所以,假设汽车也经常崩溃,并且频繁甚至严重的崩溃很常见。你会更喜欢开哪辆车?