写给初学者的建议,一些不良的代码或习惯

12rain 2011-06-29 11:55:10
最近闲的蛋疼,在论坛里四处逛了下,
先写点个人建议,有想到再补充,仅供参考。


1) 注意换行

不要写类似代码:
  if SomeCondition then Exit;


换行最重要的好处:
方便设置断点 :-)


2)把业务相关或者相对重要的属性(例如SQL语法之类),
写在单元代码中,
而不要在属性编辑器中去设置它。

虽然在Delphi的属性窗口中,会粗体显示设置过的属性,
但出了问题仍然远不如在代码中写好查。

属性编辑器中可以设置的是一些无关紧要的界面相关属性。


3)循环中避免使用FieldByName

FieldByName本身是一个循环操作,根据名称从Dataset中找到
相应的字段,这样数据量比较大时会耗用不少时间,效率低下。

而应该在循环前使用变量记录它,
类似这样的代码:

        SomeDataset.First;
while not SomeDataset.eof do
begin
S := SomeDataset.FieldByName('SomeField').AsString;
SomeDataset.Next;
end;


建议改成:

        SomeField := SomeDataset.FieldByName('SomeField');
SomeDataset.First;
while not SomeDataset.eof do
begin
S := SomeField.AsString;
SomeDataset.Next;
end;


其他在循环中取固定对象的操作,建议也做类似处理,
一提高效率,二方便维护。


4)不要到处使用
select * from

如果没有用到所有的字段,建议都改成只取使用到的字段,
效率会高很多,例如:
select field1, field2 from ...

5)尽量少用第3方控件

记住3个原则
a) 如果非必要,不要使用第3方控件。特别是不要为了界面花哨去使用它。
b) 如果非要使用,尽量用商业控件。
c) 切忌在1个项目中同时使用多套类似功能(例如界面显示)的第3方控件。
...全文
343 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
SQLDebug_Fan 2011-07-04
  • 打赏
  • 举报
回复
在使用三方控件的时候,应具备修改的能力。
qxcsdn 2011-07-04
  • 打赏
  • 举报
回复
支持!
12rain 2011-07-04
  • 打赏
  • 举报
回复
说完执行效率,再说开发效率。

你说开发效率会比较高,如果你指的是你个人的开发效率,
我是相信的。我的看法是这样:

如果你长期习惯了写这样的代码,
那你写这种风格代码的效率估计也会比较高,
熟能生巧嘛:-)

12rain 2011-07-04
  • 打赏
  • 举报
回复
对Delphi原生代码TCustomTreeView.LoadFromFile的优化:

单元名称:ComCtrls.pas
过程:TTreeStrings.LoadTreeFromStream
Author: 12rain


查看原代码可以发现在循环中有多处使用到Node.Level的代码、
而该过程会从所有节点中找寻对应的等级。在节点比较多比较复杂的情况
下会耗用大量的时间:


function TTreeNode.GetLevel: Integer;
var
Node: TTreeNode;
begin
Result := 0;
Node := Parent;
while Node <> nil do
begin
Inc(Result);
Node := Node.Parent;
end;
end;


一个简单的方法是声明一个变量记录当前的NodeLevel
更改后的外部测试代码如下:



function _GetBufStart(Buffer: PChar; var Level: Integer): PChar;
begin
Level := 0;
while Buffer^ in [' ', #9] do
begin
Inc(Buffer);
Inc(Level);
end;
Result := Buffer;
end;

procedure _LoadTreeFromStream(Owner: TTreeNodes; Stream: TStream);
var
List: TStringList;
ANode, NextNode: TTreeNode;
ALevel, i: Integer;
CurrStr: string;
ANodeLevel: Integer;
begin
List := TStringList.Create;
Owner.BeginUpdate;
try
try
Owner.Clear;
List.LoadFromStream(Stream);
ANode := nil;
ANodeLevel := 0;
for i := 0 to List.Count - 1 do
begin
CurrStr := _GetBufStart(PChar(List[i]), ALevel);
if ANode = nil then
ANode := Owner.AddChild(nil, CurrStr)
//else if ANode.Level = ALevel then
else if ANodeLevel = ALevel then
ANode := Owner.AddChild(ANode.Parent, CurrStr)
//else if ANode.Level = (ALevel - 1) then
else if ANodeLevel = (ALevel - 1) then
begin
ANode := Owner.AddChild(ANode, CurrStr);
Inc(ANodeLevel);
end
//else if ANode.Level > ALevel then
else if ANodeLevel > ALevel then
begin
NextNode := ANode.Parent;
Dec(ANodeLevel);
//while NextNode.Level > ALevel do
while ANodeLevel > ALevel do
begin
NextNode := NextNode.Parent;
Dec(ANodeLevel);
end;
ANode := Owner.AddChild(NextNode.Parent, CurrStr);
end
else;
end;
finally
Owner.EndUpdate;
List.Free;
end;
except
Owner.Owner.Invalidate; // force repaint on exception
raise;
end;
end;

procedure _LoadFromStream(ATreeView: TTreeView; Stream: TStream);
begin
_LoadTreeFromStream(ATreeView.Items, Stream);
end;

procedure _LoadFromFile(ATreeView: TTreeView; const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead);
try
_LoadFromStream(ATreeView, Stream);
finally
Stream.Free;
end;
end;



测试的结果是大约10个层次的TreeView,使用
_LoadFromFile(TreeView1, ...
会比它原来的
TreeView1.LoadFromFile
快了大约1倍左右,如果层次更多的话差异应该会更大。



12rain 2011-07-04
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 daiguan 的回复:]

最后还有效率问题,我认为效率至少应该包括2个,1个是运行效率,1个是开发效率,开发人员必须均衡的考虑这2个东西,比如说FieldByName吧,虽然他的效率更低些,但是对于只有一般只有10多个字段的表,他带来的效率影响小的可怜,0.01S和0.1S有区别吗?但是如果每个地方都这么写,那开发效率可还是要下降了,除非你们公司是那代码行数给钱的,否则真不推荐。其实很多时间我还这么写 Data=DataSet['FieldName'],这个性能应该更低,但是程序写起来更快,看起来更直接。
[/Quote]


关于FieldByName的使用,你没有理解我所说的。
你说的其他几点也很成问题。

OK,我就先给你详细说说这个FieldByName。

1) 首先注意看我的原文:
“循环中避免使用FieldByName”。

单执行一次FieldByName,所耗用的时间是细微的,
可能就是0.01秒之类的,这个效率差异完全可以忽略不计。

但是在循环中使用,这个差异会被成倍放大。
比如Dataset有1万笔数据记录,
遍历Dataset(类似Dataset.First...Dataset.Next这样的代码),
算算看 0.01秒*10000=100秒。
如果做大的数据项目应用,几十万上百万数据,这样的效率问题就是致命的。

2) 其次我们具体看看delphi中的FieldByName代码,看看里边做了什么,


function TDataSet.FieldByName(const FieldName: string): TField;
begin
Result := FindField(FieldName);
if Result = nil then DatabaseErrorFmt(SFieldNotFound, [FieldName], Self);
end;

function TDataSet.FindField(const FieldName: string): TField;
begin
Result := FFields.FindField(FieldName);
if (Result = nil) and ObjectView then
Result := FieldList.Find(FieldName);
if Result = nil then
Result := FAggFields.FindField(FieldName);
end;

function TFields.FindField(const FieldName: string): TField;
var
I: Integer;
HashValue: Cardinal;
begin
if FList.Count > 0 then
begin
HashValue := TNamedItem.HashName(FieldName);
for I := 0 to FList.Count - 1 do
begin
Result := FList.Items[I];
if (Result.FFieldNameHashValue = HashValue) and
(AnsiCompareText(Result.FFieldName, FieldName) = 0) then
Exit;
end;
end;
Result := nil;
end;

可以看到,每执行一次FieldByName,都会从字段列表中,一个个根据名称进行比较,
找到相应的字段。而这个列表是没有排序过的,效率并不高。


这样就出现第1点中所提到的,
在两种情况下,会出现比较严重的效率问题:
a) 字段比较多
b) 数据记录比较多


3)Delphi中类似FieldByName的代码还有比如TTreeView的节点的Level属性,
(TTreeNode.GetLevel),不要小看这些效率上的差异,
有时结果可能会超出你的想象。

比较早以前我有对Delphi的TTreeView代码做过类似优化和测试,
我会一起贴出来供参考,也许对理解上面所说的会有所帮助。

StarTower 2011-07-03
  • 打赏
  • 举报
回复
其实平常不怎么用第三方控件的 不太喜欢
rainychan2009 2011-07-03
  • 打赏
  • 举报
回复
if SomeCondition then Exit;
如果 SameCondition就是一个布尔变量的话,个人认为这样写还是很清爽简便的。if then ;本来就是一句话。
daiguan 2011-07-03
  • 打赏
  • 举报
回复
if ... then exit;
如果就是这么一句,应该是没什么大问题,把程序调试的希望都寄托在断点上,其实也是个很不好的习惯。
此外关于三方控件,最大的问题还是不会维护管理控件罢了,很多大型项目你不用三方,开发成本大的不可思议。另外就是VCL本身,BUG也是相当多的,而VCL的后继版本,很多也是直接从三方控件那里买来的,比如TeeChar,Indy,一个不会管理三方资源的团队,本身就不是一个成熟的团队。

最后还有效率问题,我认为效率至少应该包括2个,1个是运行效率,1个是开发效率,开发人员必须均衡的考虑这2个东西,比如说FieldByName吧,虽然他的效率更低些,但是对于只有一般只有10多个字段的表,他带来的效率影响小的可怜,0.01S和0.1S有区别吗?但是如果每个地方都这么写,那开发效率可还是要下降了,除非你们公司是那代码行数给钱的,否则真不推荐。其实很多时间我还这么写 Data=DataSet['FieldName'],这个性能应该更低,但是程序写起来更快,看起来更直接。
ADSLAN 2011-07-03
  • 打赏
  • 举报
回复
if SomeCondition then Exit;
有时候也喜欢这样写 主要是代码看上去简练。
不过被楼主一提醒,主要是不好下断点判断了
cntigercat 2011-07-03
  • 打赏
  • 举报
回复
if ... then exit;
我就是这样写的。。。呵呵
ERR0RC0DE 2011-07-03
  • 打赏
  • 举报
回复
给建议:尽量多看VCL的源码风格及习惯,以它作为自己的标准,尽量不要有自己的风格
linghengmao 2011-07-02
  • 打赏
  • 举报
回复
最好要用有源碼的第三方控件。
仙侣步惊云 2011-07-01
  • 打赏
  • 举报
回复
如果不使用fastreport、Ehlib等第三方组件,有些项目还真不怎样做。
delphi的魅力就在于第三方组件,这是真正做过商业项目和纸上谈兵者的差异。
山东蓝鸟贵薪 2011-07-01
  • 打赏
  • 举报
回复
努力学习,加强代码的易读性.............
zoologist 2011-06-30
  • 打赏
  • 举报
回复
挺好的~

kwer 2011-06-30
  • 打赏
  • 举报
回复
基本都赞同,特别是三方控件致使维护代码时候很头疼。

另:dataset datasource这些用自定义的函数create似乎要更好一些

浩南_哥 2011-06-29
  • 打赏
  • 举报
回复
第五点 严重同意 第三方控件时不时就给我来个惊喜,让我爽的蛋疼
onlyou13 2011-06-29
  • 打赏
  • 举报
回复
不尽同意...
山东蓝鸟贵薪 2011-06-29
  • 打赏
  • 举报
回复
谢谢赐教,以前我写DELPHI程序都这样写,有时"调试"
就有点难.......
Frank.WU 2011-06-29
  • 打赏
  • 举报
回复
三方控件可以用,但是最好不要超过三种。
加载更多回复(8)

828

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧