delphi – 为什么TEnumerable可以使用直通方法?

前端之家收集整理的这篇文章主要介绍了delphi – 为什么TEnumerable可以使用直通方法?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
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]不同,不可能使用更多的返回类型来覆盖一个祖先方法,所以为了改变后代的返回类型,需要应用同样的技巧.

优化还可能允许内联MoveNext和GetCurrent方法调用,因为静态编译器很难“查看”虚拟调用并且仍然很快.

[1] C对覆盖方法支持返回值协方差.

猜你在找的Delphi相关文章