2015-04-27 5 views
38

Nach dem Upgrade auf XE8 beginnen einige unserer Projekte Daten zu brechen. Sieht wie ein Fehler in TList Realisierung aus.Delphi XE8 Fehler in TList <T>, benötigen Abhilfe.

program XE8Bug1; 
{$APPTYPE CONSOLE} 

uses 
    System.SysUtils, Generics.Collections; 

type 
    TRecord = record 
    A: Integer; 
    B: Int64; 
    end; 

var 
    FRecord: TRecord; 
    FList: TList<TRecord>; 

begin 
    FList := TList<TRecord>.Create; 
    FRecord.A := 1; 
    FList.Insert(0, FRecord); 
    FRecord.A := 3; 
    FList.Insert(1, FRecord); 
    FRecord.A := 2; 
    FList.Insert(1, FRecord); 
    Writeln(IntToStr(FList[0].A) + IntToStr(FList[1].A) + IntToStr(FList[2].A)); 

end. 

Dieser Code druckt "123" in XE7 und vor (wie es sein sollte), aber in XE8 druckt es "120". Vielleicht kennt jemand einen Quickfix dafür?

Update: inoffizielle Update ist here

+9

Die generischen Sammlungen haben in XE8 neu implementiert worden. Vielleicht haben sie bei Emba keine Unit-Tests. Wenn dies so ist, wie Sie es beschreiben, und es wahrscheinlich ist, ist Ihre Lösung, auf XE7 zu bleiben. Sie müssen einen Fehlerbericht einreichen. –

+3

Berichtet als [Regression: TList . Einfügen funktioniert nicht] (https://quality.embarcadero.com/browse/RSP-10773). –

+10

Es scheint also, dass Embarcadero kein effektives Testsystem hat. Wie um alles in der Welt konnten sie das falsch verstanden haben? Solch eine grundlegende Klasse. Ein gut geführtes Entwicklerteam hätte dies umfassend getestet. Solch ein Fehler sollte niemals über diesen Test hinausgehen. Dismal. –

Antwort

32

ich, dass jetzt der TList<T>.Insert Methodenaufruf TListHelper.InternalInsertX ist abhängig von der Datengröße, in meinem Fall gefunden:

procedure TListHelper.InternalInsertN(AIndex: Integer; const Value); 
var 
    ElemSize: Integer; 
begin 
    CheckInsertRange(AIndex); 

    InternalGrowCheck(FCount + 1); 
    ElemSize := ElSize; 
    if AIndex <> FCount then 
    Move(PByte(FItems^)[AIndex * ElemSize], PByte(FItems^)[(AIndex * ElemSize) + 1], (FCount - AIndex) * ElemSize); 
    Move(Value, PByte(FItems^)[AIndex * ElemSize], ElemSize); 
    Inc(FCount); 
    FNotify(Value, cnAdded); 
end; 

Ich sehe das Problem in ersten Move Anruf. Ziel sollte sein:

PByte(FItems^)[(AIndex + 1) * ElemSize] 

nicht

PByte(FItems^)[(AIndex * ElemSize) + 1] 

Aaargh!

Schließlich habe ich die System.Generics.Defaults.pas und System.Generics.Collections.pas Einheiten von Delphi XE7 in meinen Projekten verwendet, und jetzt alles funktioniert wie erwartet.

Update: wie ich sehe, RTL nicht betroffen, da sie nicht verwenden TList<T>.Insert für T mit SizeOf> 8 (oder vielleicht ich etwas verpasst?) Ist

+0

Patchen Sie die Methode und Sie sind startklar. –

+3

Das Reparieren durch Wiederherstellen der XE7-Implementierung ist keine so schlechte Idee. Sie haben mehr Vertrauen in es. Ja, Sie können diese eine Methode reparieren, aber wundern Sie sich nicht, was sie sonst falsch verstanden haben? –

+1

Wenn Sie die gesamten Einheiten austauschen, sollten Sie die RTL/VCL/FMX usw. auch mit den festen Einheiten verwenden. Andernfalls können Sie durch andere Manifestationen dieses Defekts verletzt werden. –

Verwandte Themen