gpt4 book ai didi

delphi - 为什么 TEnumerable 使用传递方法?

转载 作者:行者123 更新时间:2023-12-03 14:38:07 25 4
gpt4 key购买 nike

TEnumerable<T> ,所有 Generics.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>同样声明一个公共(public) MoveNext 方法和一个私有(private) DoMoveNext 函数,MoveNext 除了调用 DoMoveNext 之外什么也不做。

除了增加额外的函数调用开销、使调用堆栈更长以及在试图从这些基类继承的编码人员的头脑中造成困惑之外,谁能向我解释一下它的用途是什么?这种构建它的方式有任何实际的优点吗?因为如果有的话我看不到它......

最佳答案

免责声明:我写了TEnumerable<T> 。如果我再做一次,我可能会以更低的性能和更简单的方式编写它,因为我了解到这种优化让很多人感到困惑。

它旨在避免 for-in 中的虚拟调用循环,同时保持与多态性的兼容性。这是一般模式:

  • 基类 Base定义 protected 虚拟抽象方法 V和公共(public)非虚拟方法MM发送至 V ,因此通过 Base 进行多态调用- 类型变量将路由到 V 的覆盖行为.

  • 后代类,例如 Desc实现 M 的静态覆盖(隐藏 Base.M )其中包含实现,并实现 V 的覆盖调用 Desc.M 。来电M通过Desc类型变量直接进入实现,无需虚拟调度。

具体示例:当编译器为此序列生成代码时:

var
someCollection: TSomeCollection<TFoo>;
x: TFoo;
begin
// ...
for x in someCollection do
// ...
end;

...编译器查找名为 GetEnumerator 的方法关于 someCollection 的静态类型,以及一个名为 MoveNext 的方法它返回的类型(对于 Current 属性也类似)。如果该方法具有静态调度,则可以消除虚拟调用。

这对于循环来说是最重要的,因此 MoveNext/Current访问器。但为了使优化发挥作用, GetEnumerator 的返回类型方法必须是协变的,即它需要静态返回正确的派生枚举类型。但在 Delphi 中,与 C++ [1] 不同,不可能用更派生的返回类型重写祖先方法,因此出于不同的原因需要应用相同的技巧,以更改后代中的返回类型。

优化还可能允许内联 MoveNextGetCurrent方法调用,因为静态编译器很难“看穿”虚拟调用并且仍然保持快速。

[1] C++ 支持重写方法的返回值协方差。

关于delphi - 为什么 TEnumerable<T> 使用传递方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1230054/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com