Visual C# .NET 利弊例谈 - Wecan's Weblog

来源:百度文库 编辑:神马文学网 时间:2024/04/28 21:42:00
Visual C# .NET 利弊例谈
by wecan in技术文档 at2005年7月7日04:27星期四

微软推出Visual C#.NET已经超过半年,.NET Framework作为下一代的开发工具,拥有着许多以往的RAD开发工具不可比拟的优势。其中最大的两个亮点就是强化的IDE和封装得更加完整且便于使用的System等对象;这些特性使得微软可以将面向对象编程的优势表现得淋漓尽致。众所周知,.NET Framework的特点在于高度集成了诸如COM、移动设备编程功能等,但笔者却想通过一些普通的Win32应用程序开发过程来比较一下Visual C#.NET和其它RAD的开发方便程度以及程序健壮性等问题。下面,让我们一起来通过一个笔者亲写过实例来看看使用Visual C#.NET编程的利弊。
编程的任务是通过深度优先遍历一颗目录树,枚举其中的某种扩展名的文件,寻找相应的另一种扩展名的文件是否存在并输出不存在相应扩展名文件的列表。比如ABCD.EXE文件需要一个ABCD.TXT作为对应文件,若ABCD.TXT不存在,则ABCD.EXE就将被列入输出的列表。文件的扩展名和目录树都由用户给定,并且要求要有一个比较有亲和力的用户界面。
首先,我们使用传统的RAD开发工具——Borland C++ Builder 6来开发这个应用程序。在编程思路极其简单,但在代码上却很容易出错。通过笔者的实践,发现使用C++ Builder的VCL提供的FindFirst()、FindNext()和FindClose()函数在代码实现上并不流畅,代码思想上也难以一下子接受。除了要使用while do循环外,配合使用的ChDir()函数也得用上,而且必须有寻找子节点和父节点的参数(幸亏BCB都提供了这些参数)。另外,由于文件和目录的混排,目录和文件的区分判断也显得庞大。下面是递归函数的完整代码:
void SearchDir(String filename){
TSearchRec curfile;
AnsiString filename1;
ChDir(filename);
//ShowMessage(filename);
if (FindFirst(filename+"*.*",faAnyFile,curfile) == 0) {
//ShowMessage("OK");
do
{
if ( (curfile.Attr & faDirectory) && curfile.Name != "." && curfile.Name != ".." ) {
SearchDir(ExpandFileName(curfile.Name)+"\\");
}
else
{
if (DirectoryExists(ExpandFileName(curfile.Name)) == false)
{
filename1 = ExpandFileName(curfile.Name).SubString(0,ExpandFileName(curfile.Name).Length()-frmMain->edtExt1->Text.Length());
//ShowMessage(filename1);
if ( (FileExists(filename1+frmMain->edtExt2->Text) == false) && (FileExists(filename1+frmMain->edtExt1->Text) == true) ) {
frmMain->lstResult->Items->Append(ExpandFileName(curfile.Name));
}
}
}
} while ( FindNext(curfile) == 0 );
FindClose(curfile);
}
ChDir("..");
}
容易引起我们注意的地方包括多次使用的ExpandFileName()函数以及大量的字符串操作。这都不得不令我们担心程序的运行效率会遭受影响。由于多次判断DirectoryExists()和FileExists(),效率也会受到影响。从整体上看,这是一个普遍意义上的枚举算法,转化为二叉树后的时间复杂度约等于O(2^N)。还有一点,就是这个程序需要用到模操作。
下面我们来看看Visual C#.NET的递归函数。
private void  SearchDir(string fsoname)
{
foreach ( string fsoname1 in System.IO.Directory.GetFileSystemEntries(fsoname) )
{
if ( System.IO.Directory.Exists(fsoname1) )
{
SearchDir(fsoname1);
}
else
{
if (fsoname1.ToUpper().EndsWith(edtExt.Text.ToUpper()))
{
string fsoname2 = (fsoname1.Substring(0,fsoname1.Length-edtExt.Text.Length) + edtExt2.Text);
if (System.IO.File.Exists (fsoname2) == false)
{
lstResult.Items.Add(fsoname1);
}
}
}
}
}
看完这个笔者自己写的程序后,就连笔者自己也不得不赞叹程序的简单和思路的清晰。整个程序就像英文短文一样易于阅读和理解,而且仅用到了System对象和简单的字符串操作。令人惊喜的是,由于在C#中字符串也是对象,它的操作非常简单,很多函数已经转化为对象的方法了,比如fsoname1.ToUpper().EndsWith()方法,这样就可以最大程度避免程序员找函数参数括号之苦了。而在BCB的程序中,我们随处可见括号而且十分难于对应。
System对象在这个过程中所扮演的角色最令人注目;大约40%的代码都被它节省下来了,而且从代码中我们可以强烈感受到,使用这个对象十分的简单。
这仅仅是代码编写的最终结果,在编写过程中,Visual C#.NET的文本编辑器的表现也明显好于BCB,BCB的上下文提示在一旦出现暂时性语法错误时就会中止,而且文字的加粗并非十分科学。而C#的文本编辑器不仅提供了括号的自动瞬间加粗对应功能外,上下文提示和语法检查也十分完整、迅速。
以上所提及的都是Visual C#.NET的优点,但是作为一个新生的RAD开发工具,C#也有许多不足,最致命的就是软件的运行效率和程序的兼容性。
首先我们来测试一下上面的程序的效率。乍看起来BCB的程序要比C#复杂许多,但是程序的运行效率却证明了BCB的编译器要明显优于.NET Framework的。在P4 1.8GHz/1024MB/Windows XP的环境下,对2300个文件进行配对,C++Builder的程序花了不到300毫秒的时间(包括输出),而C#的程序算上输出几乎花去了2500毫秒。这还不要紧,软件的启动速度差别也很大,C++Builder的程序启动时间几乎可以忽略不计,而C#的程序需要3秒左右才能看到主界面,这或许和C#特有的InitializeComponent()过程有关吧。
软件运行速度的不理想似乎已经是微软的嗜好了,因为他们总期待摩尔定律的庇护。但是,另一个.NET Framework不可忽视的问题就是,运行所有.NET Framework程序都需要.NET Framework的程序再发行包,而这个包不随现在市面上除了Windows Server 2003以外的任何操作系统提供。要是这个包也和Visual Basic以往的运行库那样也就罢了,偏偏这个包天生肥胖,竟有23.2MB。而拥有大量用户群的Windows 98/ME/2000/XP系统都必须先安装.NET Framework才能运行Visual C#.NET的程序。还有更气人的,这个包的安装需要的先决条件包括了安装有Internet Explorer 5.01或更高版本和Windows Installer。这些软件尤其是Windows Installer在中国的很多计算机上还不能算普及,这也使得.NET Framework开发出来的应用程序更像是玩具而不是用来解决实际问题的。笔者有一个很好的朋友,调试了近两个小时也没把.NET Framework装上,原因是他的Windows XP会在安装.NET Framework时提示拒绝访问Windows Installer服务。
C++Builder的应用程序兼容性一直是Borland所自豪的,这种兼容性甚至还包括了跨平台的可移植性。在这点上,自私的微软是不可能做到的。在我们刚刚提到的那个例程中,一个编译好的EXE文件(可以独立运行,不需要BPL或DLL)也仅是529KB。虽然Visual C#.NET的目标程序更小,但23.2MB的“先决条件”已经扼杀了大量宝贵的用户群。
综上所述,Visual C#.NET的新特性对于提高编程效率,改善编程体验有着重要的意义,但是微软应该放下自己的老大架子,再花心思好好提升一下软件的运行效率,.NET Framework才能真正被广大程序员所接受。不然,C#带来的开发上的方便并不会吸引那些有编程经验的程序员们,因为对于绝大多数程序员来说,程序的健壮性是最重要的。相信微软也不希望.NET战略的核心——.NET Framework只是一个初学者的玩具。
Visual C#.NET前途光明,要走的路却十分曲折,让我们拭目以待吧。