Отказ от ответственности: Я написал TEnumerable<T>
. Если бы я сделал это снова, я бы написал это с меньшей производительностью и большей простотой, поскольку я понял, что эта оптимизация сбивает с толку многих людей.
Он предназначен для предотвращения виртуального вызова в циклах for-in
при сохранении совместимости с полиморфизмом. Это общая схема:
Базовый класс Base
определяет защищенный виртуальный абстрактный метод V
и открытый не виртуальный метод M
. M
отправляет 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], невозможно переопределить метод предка с более производным типом возврата, поэтому тот же трюк необходимо применить по другой причине, чтобы изменить тип возврата у потомков.
Оптимизация также потенциально допускает встраивание вызовов методов MoveNext
и GetCurrent
, поскольку статическому компилятору очень трудно «видеть сквозные» виртуальные вызовы и при этом быть быстрыми.
[1] C ++ поддерживает ковариацию возвращаемых значений в переопределенных методах.