写程序,完成功能是最基本的要求,但要应对真实世界的各种情况,则会追求多种目标,如性能、稳定性、可扩展性、可维护性等。然而,在某一个历史阶段,有些目标之间是相互冲突的,需要程序设计人员选择合适的策略,在冲突与矛盾中寻求平衡,以达到最佳的综合效果。其中,效率和可靠性是一对矛盾,需要小心面对。
举个例来说,使用asp.net从SQL Server数据库中读取数据时,我们一般会使用SqlDataReader。.如: SqlDataReader reader = cmd.ExecuteReader();
获得reader对象之后,一般采用循环语句逐条读出记录,如
while(reader.Read())
{
reader[“UserName”].value.ToString();
reader.GetString(1);
}
在上面的循环语句中,我采用了两种方法来读取数据。第一个语句读取记录的第1个字段:UserName,并将其转换成字符串,第二条语句直接根据索引号,返回字符串。已经有很多文章说明,用第2条语句的方法比用第1条语句的方法,效率更高(可以去理解和测试一下)。
毫无疑问,我在程序中会追捧第2第语句的方法,即便只会带来少许的性能提高,在成千上万次数据读取中,差别就明显了。
根据效率优先原则,我选择了第2条语句所采用的方法来读取数据。但问题犹如幽灵,总会在你得意时对你当头一棒!假设字段的内容为空(在这数据库表中大量存在)时,你将会遭遇一个错误:“数据为空。不能对空值调用此方法或属性。”这个错误会让你手足无措。
但是,你采用第1条语句的方法,在字段值为空时,却不会有前面的错误。由此可推断,微软在实现GetString()时,并没有打算处理数据为空的情况。效率优先原则在这里遭遇了挫折。系统漏洞百出,再高的效率也没有多大意义,尤其对于面向公众的信息网站来讲,更是这样。
是不是就放弃第2条语句的方法,全部采用第1条语句的方法呢?如果能够尽可能利用两种方法的优点就更好了。
解决这个问题就要摒弃一刀切,根据具体情况具体分析。如果字段在定义时就不能为空的,就可以不用考虑空值的情况,采用第2条语句的方法,以提高效率。如果字段定义可以为空时,则采用第1条语句的方法,以提高可靠性。
当然,也可以先进行空值判断,再采用第2条语句的方法,如:
string userName = reader.IsDBNull(1)?null:reader.Getstring(1);
这样,就可以在保证可靠性和提高效率之间都有所照顾。
类似这样的效率与可靠性之间的矛盾,在程序中大量存在。有时可能为了应付发生概率很小的意外,却要写上大段大段的代码来进行检测、分析和处理。
从某处看了一段使用FileUpload控件来上传图象的代码。点击浏览按钮,可以选择相应图片文件,并使文件全路径显示在控件的文本框中。然后再通过一段代码来实现上传:
imagePath = upImage.PostedFile.FileName;
//
取得图片类型
imageType = imagePath.Substring(imagePath.LastIndexOf(".") + 1);
//
取得图片名称
imageName = imagePath.Substring(imagePath.LastIndexOf("//") + 1);
string tmp = imageName.Split('.')[0];
string hashImageName =tmp.GetHashCode().ToString() + "." + imageType;
//
判断是否指定图片格式
if ("jpg" == imageType || "JPG" == imageType || "gif" == imageType || "GIF" == imageType || "bmp" == imageType || "BMP" == imageType || "Bmp" == imageType)
{
imageUrl = "~/Images/" + hashImageName;
try
{
//
建立虚拟路径
mPath = Server.MapPath("~/Images");
//
保存到虚拟路径
upImage.PostedFile.SaveAs(mPath + "//" + hashImageName);
Response.Write("
图片上传成功!"
);
}
catch(Exception err)
{
Response.Write(err.Message + ",
图片上传失败!"
);
}
}
else
{
Response.Write("<script language='javascript'> alert('
对不起!请您选择jpg/bmp/gif格式的图片!');</script>"
);
return;
}
}
这一段代码,对文件格式进行了判断,如果格式是指定的图片格式之一,则执行上传。一般情况下,这段程序没有问题。但是,当我选择了图片之后,却人为修改了控件文本框中的路径和文件信息,修改后的文件可能并不存在,此时会发生什么呢?
我曾以为程序不会正常运行,上传图片会失败。然后实验的结果却是显示了“图片上传成功!”。查看服务器上图片文件夹,发现确实有了指定的文件名,但图像大小为0字节。这说明这个成功的信息是个假象!(看来有必要去理解SaveAs()的真实原理)。
为了防止原文件不存在,却能上传成功的假象出现,在进行上传之前,有必要对原文件是否存在进行验证。于是我前面的代码前加了一个判断语句:
if
(File.Exists(upImage.PostedFile.FileName))
{
}
这样,就可以得到这样一个逻辑:

这一个流程图,两次判断对于大多数操作来讲,没有任何意义,如果不要这两个判断,效率会更高。但对于少数不按“规矩”办事的操作来讲,这两次判断必不可少,没有就会出现问题。
总而言之,要做优雅的程序,需要缜密的思考,仔细应对意外情况,同时尽可能保证效率,才能使程序的最大限度地接近期望的目标。