当前位置: 首页 > 科技观察

解析大型.NETERP系统代码的恶臭

时间:2023-03-18 16:55:10 科技观察

1对用户输入的约定和假设太多在配置文件App.config中有设置报表路径的配置部分:程序中有一个销售报表文件SalesReport.rpt。用代码调用这个报表可以写成:stringsalesReport=ReportPath+"SalesReport.rpt";因为路径末尾没有反斜杠,会抛出找不到报告文件的异常(FileNotFoundException)。修改后,可以考虑在配置前最后加一个反斜杠\。修改后的配置部分如下:为此,我认为在程序中应该考虑一个判断。对于默认没有反斜杠\的路径,加一个即可。程序代码只有一行:if(!reportPath.EndsWith("\\"))reportPath+="\\";这个例子也可以通过调用方法System.IO.Path.Combine来实现,防止用户输入反斜杠的问题。再举个例子,比如用户在IP地址后面没有加端口号,程序中简单判断,加了默认端口号,用户输入的值不是必须的。比较以下两种配置方式。2将数据库服务器可以处理的查询移到终端对于处理一个原因是C#有一个非常有用的foreach语句,它永远不会抛出越界异常。因此,出现了一些偷懒的做法,宁愿将数据读入程序中进行处理,也不愿优化SQL语句查询。请参考下面的代码。我遇到后直接强行重写。IPrefetchPath2prefetchPath=newPrefetchPath2((int)EntityType.SalesOrderEntity);prefetchPath.Add(PartEntity.PrefetchPathSalesOrderDetail);SalesOrderEntityorder=salesOrderManager.GetPart("SC201507",prefetchPath);字符串描述=字符串.空;foreach(SalesOrderDetailEntityorderDetailinorder.SalesOrderDetail){if(orderDetail.ItemNo="FLEX102030009"){description=entity.Description;休息;可以在数据库服务器中完成的事情不应移至代码中。这是低效的,代码没有质量。3数据库SQL语句不考虑重复执行或自动部署恶臭代码:ALTERTABLEJobOrderADDFiscalYearDECIMAL(4,0),PeriodNoDECIMAL(2,0)应修改为如下代码。如果不存在(SELECTC.NAMEFROMDBO.SYSCOLUMNSC,DBO.SYSOBJECTSOWHEREO.ID=C.IDANDO.NAME='CompanyParameter'ANDC.NAME='POApprovalRequired')BEGINAlterTableCompanyParameterADDPOApprovalRequired[nvarchar](1)DEFAULT'N'END4DataTable的使用中,使用数字作为索引,维护时很难看清数字列名的含义恶臭代码:stringcachePath=string.Empty;DataTabletable=queryManager.FetchTableBySqlCommand(query);foreach(DataRowrowintable.Rows)cachePath=row.ItemArray[2].ToString();应该修改为以列名作为索引:();5字符串运算不考虑大小写字符串可以使用等号(=)运算符进行判断和比较。我推荐的方式是用Equal方法,传入的参数是否区分大小写。字符串搜索还需要考虑大小写问题,比如下面的代码,不区分大小写的搜索。字符串findWath="SO2015";if(txtOrderNo.Text.IndexOf(findWhat,0,StringComparison.InvariantCultureIgnoreCase)!=-1)string.IsNullOrWhiteSpace用于判断字符串的空值,string.Empty用于设置字符串的空值。6任务长时间运行时,光标未设置为等待状态,控件状态未变灰。在执行任务之前,UseWaitCursor=true;btnAdd.Enable=false;任务执行后,UseWaitCursor=false;btnAdd.Enable=true;7打开文件对话框没有设置合适的标题和文件类型过滤器。这是一个小细节。从stackoverflow中搜索几个过滤器以供参考。publicconststringImageFilter="图像文件(*.jpg,*.jpeg,*.jpe,*.jfif,*.png,*.gif,*.bmp)|*.jpg;*.jpeg;*.jpe;*.jfif;*.png;*.gif;*bmp";publicconststringPDFFilter="PDF文件(*.pdf)|*.pdf";publicconststringExcelFilter="ExcelFiles|*.xls;*.xlsx;*.xlsm";#p#8删除数据时,如果不是必须的,不需要先读取到客户端再删除。如果有校验逻辑,可以考虑将过滤条件传递给数据库来校验数据,而不是读取数据给程序来校验。9日期时间不考虑小时和分钟值。DateTime.Now有小时和分钟,而DateTime.Today没有时间。有一次今天做的日记数据查不到,总是要求客户把查询的时间范围提前一天,因为DateTime.Now有小时和分钟值。10SQL脚本文件编码保存格式为UTF8,避免GB2312或BIG5造成的乱码。11同一个数据库中有多个命名约定。SalesOrder将Sales_Order的首字母大写,并用下划线分隔单词。SL_Sales_Order添加模块前缀。12系统默认值的来源不是基于采购订单。的三个值依次为85,15,5。这些默认值应该用一个函数来存储,而不是直接在代码中硬编码默认值。13常量值不一致主要是由于日期和时间的最小值。建议使用以下代码设置公共变量值。私有静态只读DateTime_dateTimeMinValue=newDateTime(1753,1,1,0,0,0,0);私有静态只读DateTime_dateTimeMaxValue=newDateTime(2099,12,31,0,0,0,0);公共静态日期时间DateTimeMinValue{得到{返回_dateTimeMinValue;}}publicstaticDateTimeDateTimeMaxValue{get{return_dateTimeMaxValue;}}数据库中的时间值是一个空值字段,可以设置为NULL或DateTimeMinValue。对于特殊的财务报表,必须有一个时间范围,使用DateTimeMinValue。myEntity.SetNewFieldValue((int)MyEntityFieldIndex.MyDateField,null);14没有数据绑定的力量WinForms数据绑定是双向的,可以通过数据源控件获取实体对象到DataGridView控件。臭味代码:stringcustomerName=gridQuotation.Rows[0].Cell[0].Value;应该是:QuotationEntityquotation=detailBindingSource.CurrentasQuotationEntity;QuotationEntityquotation=this.gridQuotation.GetRowListObject(row)asQuotationEntity;stringcustomerName=quotation.CustomerName15不借助.NET正则表达式的数据验证。难闻的气味:试试{Convert.ToDecimal("123abc456");返回真;}catch{returnfalse;}应该是Regexregex=newRegex("a{1,2}");Matchm=regex.Match("123abc456")if(m.Success){//验证成功}可以将这些验证方法封装成public方法,实现代码复用。16数据库查询不考虑NULL值。难闻的代码:ResultsetFieldsfields=newResultsetFields(1);fields.DefineField(PurchaseRequisitionDetailFields.Qty,0);应该是:DbFunctionCalldbFunQty=newDbFunctionCall("ISNULL",newobject[]{PurchaseRequisitionDetailFields.Qty,0});EntityField2efieldQty=newEntityField2(PurchaseRequisitionDetailFields.Qty.Name,dbFunQty);itemFields.DefineField(efieldQty,0);等同于ISNULL函数调用ISNULL(Qty,0)。