Почему делает TEnumerable <T>, используют методы передачи?

  1. Обеспечивают канал RSS, таким образом, они не съедают Вашу пропускную способность.
  2. При покупке, заставьте всех ожидать случайный количество времени до 45 секунд или чего-то, в зависимости от того, что Вы ищете точно. Точно, каковы Ваши ограничения синхронизации?
  3. Дают всем 1 минуту, чтобы поставить их имя в для рисунка и затем случайным образом выбрать людей. Я думаю, что это - самый справедливый путь.
  4. Монитор учетные записи (включают несколько раз в сессию и хранят его?) и добавляют задержки с учетными записями, которые кажутся, что они ниже человеческого порога скорости. Это, по крайней мере, заставит ботов быть запрограммированными, чтобы замедлиться и конкурировать с людьми.
12
задан Rob Kennedy 13 August 2009 в 17:10
поделиться

3 ответа

Отказ от ответственности: Я написал TEnumerable . Если бы я сделал это снова, я бы, вероятно, написал его с меньшей производительностью и большей простотой, поскольку я узнал, что эта оптимизация сбивает с толку многих людей.

Она разработана, чтобы избежать виртуального вызова в ] for-in при сохранении совместимости с полиморфизмом. Это общий шаблон:

  • Базовый класс Базовый определяет защищенный виртуальный абстрактный метод 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 для возвращаемого типа (и аналогично для ] Текущее свойство ). Если этот метод имеет статическую отправку, виртуальный вызов может быть исключен.

Это наиболее важно для петель, и таким образом MoveNext / Current аксессор. Но для того, чтобы оптимизация работала, возвращаемый тип метода GetEnumerator должен быть ковариантным, то есть он должен статически возвращать правильный производный тип перечислителя. Но в Delphi, в отличие от C ++ [1], невозможно переопределить метод-предок с помощью более производного типа возврата, поэтому тот же трюк необходимо применить по другой причине, чтобы изменить тип возвращаемого значения в потомках.

Оптимизация также потенциально позволяет встраивать вызовы методов MoveNext и GetCurrent , поскольку статическому компилятору очень трудно «видеть сквозь» виртуальные вызовы и при этом оставаться быстрым.

[1] C ++ поддерживает ковариацию возвращаемого значения для переопределенных методов.

тип возвращаемого значения метода GetEnumerator должен быть ковариантным, то есть он должен статически возвращать правильный производный тип перечислителя. Но в Delphi, в отличие от C ++ [1], невозможно переопределить метод-предок более производным типом возврата, поэтому тот же трюк необходимо применить по другой причине, чтобы изменить тип возвращаемого значения в потомках.

Оптимизация также потенциально позволяет встраивать вызовы методов MoveNext и GetCurrent , поскольку статическому компилятору очень трудно «видеть сквозь» виртуальные вызовы и при этом оставаться быстрым.

[1] C ++ поддерживает ковариацию возвращаемого значения для переопределенных методов.

тип возвращаемого значения метода GetEnumerator должен быть ковариантным, то есть он должен статически возвращать правильный производный тип перечислителя. Но в Delphi, в отличие от C ++ [1], невозможно переопределить метод-предок более производным типом возврата, поэтому тот же трюк необходимо применить по другой причине, чтобы изменить тип возвращаемого значения в потомках.

Оптимизация также потенциально позволяет встраивать вызовы методов MoveNext и GetCurrent , поскольку статическому компилятору очень трудно «видеть сквозь» виртуальные вызовы и при этом оставаться быстрым.

[1] C ++ поддерживает ковариацию возвращаемого значения для переопределенных методов.

27
ответ дан 2 December 2019 в 04:33
поделиться

Метод GetEnumerator () не виртуальный; вы не можете отменить это. Это один из способов гарантировать, что GetEnumerator () всегда будет существовать, всегда принимать фиксированный набор параметров (в данном случае их нет) и что какой-то программист не испортит его для классов-потомков. Любой, кто использует TEnumerable - или потомок - может вызвать GetEnumerator ().

Но поскольку будут разные потомки TEnumerable, которые делают разные вещи, DoGetEnumerator () позволяет программисту вносить изменения внутри структуры. «Виртуальный» позволяет переопределить метод. «Абстрактное» заставляет классы-потомки реализовать метод - компилятор не позволит вам забыть. А поскольку DoGetEnumerator () объявлен как защищенный (по крайней мере, на этом уровне), программист, использующий потомка TEnumerable, может '

3
ответ дан 2 December 2019 в 04:33
поделиться

Вы не сможете выполнять такие трюки, как повторное введение GetEnumerator:

function TDictionary<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>;
begin
  Result := GetEnumerator;
end;
...
function TDictionary<TKey, TValue>.TKeyCollection.GetEnumerator: TKeyEnumerator;
begin
  Result := TKeyEnumerator.Create(FDictionary);
end;

в создать соответствующий локальный / конкретный TEnumerator

3
ответ дан 2 December 2019 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: