在我维护的一些代码中,我看到TClientDataSet.OnCalcFields
事件处理程序中使用了两种不同的方法:
with DataSet do
begin
// 1. Call FieldByName twice
if AMinDate > FieldByName(SPlanAllocatieFromDate).AsDateTime then
AMinDate := FieldByName(sPlanAllocatieFromDate).AsDateTime;
// 2. Put the retrieved FieldByName value in a temp var
lEmpID := FieldByName(SPlanAllocatieEmpID).AsInteger;
if lEmpID <> 0 then lTSAllocatedEmpIDs.Add(IntToStr(lEmpID));
end;
编译器(Delphi XE2,Win32 app)是否会优化方法2以使用temp var?两个FieldByNames非常接近,您甚至可以说嵌套。
如果没有,我应该重写1.因为OnCalcFields经常执行。
顺便说一句。我知道Fields []和FieldByName(),或者在运行EOF循环时使用temp TField var,这里不是问题。
答案 0 :(得分:7)
没有任何版本的Delphi编译器会做这样的事情。
这样的优化将要求编译器能够证明对FieldByName的两次调用总是给出相同的结果,并且目前没有规定将方法标记为确定性的。
注意,在理论上(如果实际上不太可能)两个调用很可能不会给出相同的结果,在这种情况下,例如如果另一个线程在第一次和第二次调用之间删除集合中的字段。通常,编译器不知道或关心调用站点特定方法调用实际上做了什么。
答案 1 :(得分:5)
编译器是否优化(关闭)相同的
FieldByName
次呼叫?
不,不。
编译器不查看函数调用内部以查看其中的内容。因此,它无法证明连续调用函数返回的值是相同的。同样,它无法证明该功能没有副作用。这些是正在考虑的优化的两个先决条件。
您需要自己执行优化,方法是显式添加和使用局部变量来存储单个调用返回FieldByName
的值。
除了考虑性能之外,我认为使用局部变量来保持字段在语义上要好得多。这使读者清楚所有操作都在同一个字段上执行。仅凭这个原因足以说服我做出你所描述的改变。不要重复自己。
在我们处于代码审核模式时,您可能需要重新考虑使用with
。