TEnumerable< T>,所有的泛型.Collections容器类的基类都有一个非常奇怪的声明.看起来像这样:
type TEnumerable<T> = class abstract protected function DoGetEnumerator: TEnumerator<T>; virtual; abstract; public function GetEnumerator: TEnumerator<T>; end; function TEnumerable<T>.GetEnumerator: TEnumerator<T>; begin Result := DoGetEnumerator; end;
TEnumerator< T>同样声明一个公共MoveNext方法和一个私有DoMoveNext函数,MoveNext除了调用DoMoveNext之外什么都不做.
除了增加额外的函数调用开销,调用堆栈更长的时间,还是在尝试从这些基类继承的编程人员的脑海中造成混乱,任何人都可以向我解释什么目的?这样构造它有什么实际的优势,因为如果我看不到它…
解决方法
免责声明:我写了TEnumerable< T>.如果我再次做到这一点,我可能会以较少的性能和更简单的方式写下来,因为我已经知道这种优化会混淆很多人.
它旨在避免在for-in循环中的虚拟调用,同时保持与多态性的兼容性.这是一般的模式:
>基类Base定义受保护的虚拟抽象方法V和公共非虚拟方法M.M调度到V,因此通过基本类型变量的多态调用将路由到V的超行为.
> Descript类,如Desc,实现M(隐藏Base.M)的静态覆盖,其中包含实现,并实现了一个调用Desc.M的V的覆盖.通过描述类型的变量调用M直接执行,而不需要虚拟调度.
var someCollection: TSomeCollection<TFoo>; x: TFoo; begin // ... for x in someCollection do // ... end;
…编译器在静态类型的someCollection上查找一个称为GetEnumerator的方法,并在其返回的类型(以及类似于Current属性)上使用一个称为MoveNext的方法.如果此方法具有静态调度,则可以消除虚拟调用.
这对于循环是最重要的,因此是MoveNext / Current访问器.但是为了使优化工作,GetEnumerator方法的返回类型必须是协变的,也就是说,它需要静态返回正确的派生枚举器类型.但是在Delphi中,与C [1]不同,不可能使用更多的返回类型来覆盖一个祖先方法,所以为了改变后代的返回类型,需要应用同样的技巧.