Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Begrenzter String, TList und InterfaceObject > Datenmüll (https://www.delphipraxis.net/186522-begrenzter-string-tlist-und-interfaceobject-datenmuell.html)

QStorm 9. Sep 2015 09:00

Delphi-Version: 5

Begrenzter String, TList und InterfaceObject > Datenmüll
 
Hallo,

Beim Umstieg von Delphi XE auf XE8 bin ich auf folgendes Problem gestoßen:

Vorgeschichte:
Ich verwende einen auf 10 Zeichen begrenzten String als "ID".
Diesen kann ich ohne Probleme als Typ einer TList verwenden:
Delphi-Quellcode:
type
 MyID = String[10];

// ...

var
  ID1,
  ID2 : MyID;
  Liste : TList<MyID>;
begin
  ID1 := ('ABCDEFGHIJ');
  Liste := (TList<MyID>.Create);
  Liste.Add(ID1);
  ID2 := (Liste[0]);
end;
In einem TInterfacedObject verwende ich nun TList als Member:
Delphi-Quellcode:
IMyObject<T> = interface
['{22041332-1221-4EBD-BBC5-1AF3C914E08B}']
  procedure AddValue(const Value : T);
  function GetValue(const Index : Integer) : T;
end;

TMyObject<T> = class(TInterfacedObject, IMyObject<T>)
strict private
  internalList : TList<T>;
public
  constructor Create;

  procedure AddValue(const Value : T);
  function GetValue(const Index : Integer) : T;
end;

// ...

constructor TMyObject<T>.Create;
begin
  internList := (TList<T>.Create);
end;

procedure TMyObject<T>.AddValue(const Value : T);
begin
  internList.Add(Value);
end;

function TMyObject<T>.GetValue(const Index : Integer) : T;
begin
  Result := (internList[Index]);
end;
Problem:
Wenn ich ein Objekt vom Typ IMyObject<MyID> erzeuge und via AddValue eine MyID hinzufüge entsteht Datenmüll:

Delphi-Quellcode:
var
  ID1,
  ID2 : MyID;
  MyObj1 : IMyObject<MyID>;
begin
  ID1 := ('ABCDEFGHIJ');
  MyObj1 := (TMyObject<MyID>.Create);
  MyObj1.AddValue(ID1);
  ID2 := (MyObj1.GetValue(0));
end;
Wert von ID2: 'ABC'#$90'!'#$B#2#$8D'þ'#$18
Die erste 3 Zeichen sind noch korrekt, der Rest jedoch nicht.
Es sieht so aus, als wenn er nicht genügend Speicher für den String reserviert.

MyID ist ein zentraler Bestandteil der Software.

Wodurch tritt das Problem auf und wie könnte man es lösen?

Vielen Dank im Voraus

Sir Rufo 9. Sep 2015 09:08

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
XE8 oder XE8.1?

Die Generics - speziell die Listen - sind bei XE8 komplett umgestellt worden und es gibt dort einen Bug speziell mit Records - der aber auch diesen
Delphi-Quellcode:
String[10]
Typen betrifft. Behoben wurde dieser Bug mit XE8.1

https://quality.embarcadero.com/browse/RSP-11096
http://stackoverflow.com/questions/2...eed-workaround

QStorm 9. Sep 2015 09:11

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Hallo,

Ich verwende "22.0.19908.869" (XE8 Subscription Update 1).

UPDATE: Mit dem inoffiziellen Fix (http://rghost.ru/6qq87QGGX) funktioniert es leider auch nicht.

BTW: Vielen Dank für die Links.

Sir Rufo 9. Sep 2015 09:25

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Jupp, da scheint noch ein Bug zu sein ...

Mit DX10 funktioniert das auf jeden Fall

TiGü 9. Sep 2015 09:39

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Zitat:

Zitat von QStorm (Beitrag 1315241)
Wodurch tritt das Problem auf und wie könnte man es lösen?

Alternativ kannst du eventuell auch zurück auf XE7 gehen, was ja im Kaufpreis von XE8 mit enthalten ist.

mkinzler 9. Sep 2015 09:44

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Wenn der Bug in Seattle gelöst wurde, müsste er demnächst auch in XE8 (Subscription Update 2 o.ä.) gefixt werden, wurde ja für demnächst angekündigt.

Bernhard Geyer 9. Sep 2015 09:48

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Zitat:

Zitat von mkinzler (Beitrag 1315256)
Wenn der Bug in Seattle gelöst wurde, müsste er demnächst auch in XE8 (Subscription Update 2 o.ä.) gefixt werden, wurde ja für demnächst angekündigt.

Dazu müsste man bei Rückportieren wissen das es ein entsprechend relevanter Bug ist. Ist er z.B. nur wegen eines neuen Features in Seatle gefixt würde ich mich nicht darauf verlassen das er auch in XE8 korrigiert wird.

QStorm 9. Sep 2015 10:16

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Kann einer bitte die Units "System.Generics.Collections" und "System.Generics.Defaults" von Delphi XE7 posten?

Sir Rufo 9. Sep 2015 10:21

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Zitat:

Zitat von QStorm (Beitrag 1315263)
Kann einer bitte die Units "System.Generics.Collections" und "System.Generics.Defaults" von Delphi XE7 posten?

Glaube ich mal eher nicht, denn die sind urheberrechtlich geschützt!

mkinzler 9. Sep 2015 10:22

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Das dürfte nicht erlaubt sein. Diese würden mit großer Wahrscheinlichkeit auch nicht so einfach unter XE8 funktionieren.

Sir Rufo 9. Sep 2015 10:23

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Zitat:

Zitat von mkinzler (Beitrag 1315265)
Das dürfte nicht erlaubt sein. Diese würden mit großer Wahrscheinlichkeit auch nicht so einfach unter XE8 funktionieren.

Doch, funktionieren tut das, aber das Veröffentlichen ist (mir zumindest) nicht erlaubt.

stahli 9. Sep 2015 10:23

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Schreib doch mal MEissing an und frage nach einer schnellen Lösung.

Sir Rufo 9. Sep 2015 10:35

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Es gibt aber Abhilfe
Delphi-Quellcode:
program dp_186522;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Generics.Collections,
  System.SysUtils;

type
  TMyID = string[ 10 ];

  IMyObject<T> = interface
    [ '{22041332-1221-4EBD-BBC5-1AF3C914E08B}' ]
    procedure AddValue( const Value: T );
    function GetValue( const Index: Integer ): T;
  end;

  TMyObject<T> = class( TInterfacedObject, IMyObject<T> )
  strict private
    internalList: TList<T>;
  public
    constructor Create;
    destructor Destroy; override;

    procedure AddValue( const Value: T );
    function GetValue( const Index: Integer ): T;
  end;

  TWrap<T> = record
  private
    FValue: T;
  public
    class operator implicit( const a: T ): TWrap<T>;
    class operator implicit( const a: TWrap<T> ): T;
  end;

  TMyWrappedObject<T> = class( TInterfacedObject, IMyObject<T> )
  strict private
    internalList: TList<TWrap<T>>;
  public
    constructor Create;
    destructor Destroy; override;

    procedure AddValue( const Value: T );
    function GetValue( const Index: Integer ): T;
  end;

  { TMyObject<T> }

procedure TMyObject<T>.AddValue( const Value: T );
begin
  internalList.Add( Value );
end;

constructor TMyObject<T>.Create;
begin
  inherited;
  internalList := TList<T>.Create;
end;

destructor TMyObject<T>.Destroy;
begin
  internalList.Free;
  inherited;
end;

function TMyObject<T>.GetValue( const Index: Integer ): T;
begin
  Result := internalList[ index ];
end;

{ TWrap<T> }

class operator TWrap<T>.implicit( const a: T ): TWrap<T>;
begin
  Result.FValue := a;
end;

class operator TWrap<T>.implicit( const a: TWrap<T> ): T;
begin
  Result := a.FValue;
end;

{ TMyWrappedObject<T> }

procedure TMyWrappedObject<T>.AddValue( const Value: T );
begin
  internalList.Add( Value );
end;

constructor TMyWrappedObject<T>.Create;
begin
  inherited;
  internalList := TList < TWrap < T >>.Create;
end;

destructor TMyWrappedObject<T>.Destroy;
begin
  internalList.Free;
  inherited;
end;

function TMyWrappedObject<T>.GetValue( const Index: Integer ): T;
begin
  Result := internalList[ index ];
end;

procedure Test1;
var
  ID1, ID2: TMyID;
  Liste  : TList<TMyID>;
begin
  ID1   := ( 'ABCDEFGHIJ' );
  Liste := ( TList<TMyID>.Create );
  Liste.Add( ID1 );
  ID2 := ( Liste[ 0 ] );
  Assert( ID1 = ID2 );
end;

procedure Test2;
var
  ID1, ID2: TMyID;
  MyObj1  : IMyObject<TMyID>;
begin
  ID1    := ( 'ABCDEFGHIJ' );
  MyObj1 := ( TMyObject<TMyID>.Create );
  MyObj1.AddValue( ID1 );
  ID2 := ( MyObj1.GetValue( 0 ) );
  Assert( ID1 = ID2 );
end;

procedure Test3;
var
  ID1, ID2: TMyID;
  MyObj1  : IMyObject<TMyID>;
begin
  ID1    := ( 'ABCDEFGHIJ' );
  MyObj1 := ( TMyWrappedObject<TMyID>.Create );
  MyObj1.AddValue( ID1 );
  ID2 := ( MyObj1.GetValue( 0 ) );
  Assert( ID1 = ID2 );
end;

begin
  try
    Test1;
    Test2; // fails
    Test3; // pass
  except
    on E: Exception do
      Writeln( E.ClassName, ': ', E.Message );
  end;
  Readln;

end.

QStorm 9. Sep 2015 11:44

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Zitat:

Zitat von Sir Rufo (Beitrag 1315264)
Zitat:

Zitat von QStorm (Beitrag 1315263)
Kann einer bitte die Units "System.Generics.Collections" und "System.Generics.Defaults" von Delphi XE7 posten?

Glaube ich mal eher nicht, denn die sind urheberrechtlich geschützt!

Kann man sich die mit einer XE8 Lizenz irgendwo runterladen, ohne Delphi neu zu installieren (ist ja im Kaufpreis von XE8 enthalten)?

himitsu 9. Sep 2015 12:10

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Nein, ist nur verschlüsselt im Setup enthalten. (natürlich installieren mit der XE7-Lizenz)

In VM/Sandbox installieren?

QStorm 10. Sep 2015 13:48

AW: Begrenzter String, TList und InterfaceObject > Datenmüll
 
Ich danke euch allen für die Antworten und Abhilfe.


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:02 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz