Это дефект вводится в X Е8. Вот простейшее воспроизведение, которое я могу произвести.
{$APPTYPE CONSOLE}
uses
System.Generics.Collections;
var
Queue: TQueue<TArray<Byte>>;
begin
Queue := TQueue<TArray<Byte>>.Create;
Queue.Enqueue(nil);
Writeln(Queue.Count);
end.
Выходной сигнал 1 в XE7 и 0 в XE8 и Сиэтле.
Об этом сообщается Embarcadero: RSP-13196.
Реализация Enqueue
выглядит следующим образом:
procedure TQueue<T>.Enqueue(const Value: T);
begin
if IsManagedType(T) then
if (SizeOf(T) = SizeOf(Pointer)) and (GetTypeKind(T) <> tkRecord) then
FQueueHelper.InternalEnqueueMRef(Value, GetTypeKind(T))
else
FQueueHelper.InternalEnqueueManaged(Value)
else
case SizeOf(T) of
1: FQueueHelper.InternalEnqueue1(Value);
2: FQueueHelper.InternalEnqueue2(Value);
4: FQueueHelper.InternalEnqueue4(Value);
8: FQueueHelper.InternalEnqueue8(Value);
else
FQueueHelper.InternalEnqueueN(Value);
end;
end;
Когда T
динамический массив, выбирается FQueueHelper.InternalEnqueueMRef
ветвь. Это, в свою очередь, выглядит следующим образом:
procedure TQueueHelper.InternalEnqueueMRef(const Value; Kind: TTypeKind);
begin
case Kind of
TTypeKind.tkUString: InternalEnqueueString(Value);
TTypeKind.tkInterface: InternalEnqueueInterface(Value);
{$IF not Defined(NEXTGEN)}
TTypeKind.tkLString: InternalEnqueueAnsiString(Value);
TTypeKind.tkWString: InternalEnqueueWideString(Value);
{$ENDIF}
{$IF Defined(AUTOREFCOUNT)}
TTypeKind.tkClass: InternalEnqueueObject(Value);
{$ENDIF}
end;
end;
Обратите внимание, что нет записи для TTypeKind.tkDynArray
. Поскольку эти два метода встроены, inliner удается сжать все до нуля. Никакие действия не выполняются, если вы используете Enqueue
динамический массив.
В старые добрые времена XE7 код выглядел так:
procedure TQueue<T>.Enqueue(const Value: T);
begin
if Count = Length(FItems) then
Grow;
FItems[FHead] := Value;
FHead := (FHead + 1) mod Length(FItems);
Inc(FCount);
Notify(Value, cnAdded);
end;
Нет возможности для конкретных дефектов типа там.
Я не думаю, что для вас есть простой способ обхода. Возможно, наиболее целесообразным способом является принятие кода для XE7 TQueue
и использование этого вместо сломанной реализации от XE8 и Seattle. Для записи я отказался от общих коллекций Embarcadero и использовал свои собственные классы.
Предыстория здесь является то, что в X Е8, Embarcadero решил обратиться к недостатку в их реализации дженериков. Всякий раз, когда вы создаете типичный тип, создаются копии всех методов. Для некоторых методов идентичный код генерируется для разных экземпляров.
Так что для TGeneric<TFoo>.DoSomething
и TGeneric<TBar>.DoSomething
это идентичный код. Другие компиляторы для других языков, шаблоны C++, .net generics и т. Д., Распознают это дублирование и объединяют идентичные общие методы. Компилятор Delphi этого не делает. Конечный результат - это более сложный исполняемый файл, чем это необходимо.
В XE8 Эмбаркадеро решил заняться этим в том, что я считаю совершенно неправильным. Вместо того, чтобы атаковать первопричину проблемы, компилятор решил изменить реализацию своих общих классов коллекций. Если вы посмотрите на код в Generics.Collections
, вы увидите, что он полностью переписан в XE8. Если ранее код из XE7 и ранее был доступен для чтения, то из XE8 он теперь чрезвычайно сложный и непрозрачный.Это решение имеет следующие последствия:
- Комплексный код содержит много ошибок. Многие из них были обнаружены вскоре после того, как XE8 был выпущен и исправлен. Вы наткнулись на другой недостаток. Одна вещь, которую мы узнали, заключается в том, что внутренний набор тестов Embarcadero недостаточно реализует свои классы коллекций. Очевидно, что их тесты неадекватны.
- Изменяя свою библиотеку, а не компилятор, они закрепили классы RTL. Оригинальная проблема с родовым раздуванием кода остается для сторонних классов. Если бы Embarcadero исправил проблему у источника, то они не только сохранили бы простой и правильный код класса коллекции из XE7, но и получили бы все третий общий код.
Кроме того, нам не нужен еще один несовместимый тип массива байтов. Используйте 'TBytes'. В более общем случае используйте 'TArray' для типов элементов, отличных от 'Byte'. –
Согласен. Начальный массив TidBytes (Indy) – Hans
Что не работает? –