![]() |
Kopieren des Inhalt eines Record
Hallo Forum,
gibt es eine einfachere Möglichkeit? Ich arbeite häufig mit TList Objekten in denen ich Records verwalte. Beispiel
Delphi-Quellcode:
dieser wird in der Liste über
type PTest = ^TTest
TTest = record s1 : String; d1 : Double; i1 : Integer; s2 : String; l1 : LongInt; s3 : String; n1 : Int64; end;
Delphi-Quellcode:
hinzugefügt.
.Add( P ); // P : PTest
Wenn ich nun den Inhalt eines Records in einen neuen kopieren möchte erfolgt dies in ähnlicher Forem wie..
Delphi-Quellcode:
Falls im Record eine Variable hinzugefügt wird muss dies immer in der Kopierroutine nachgezogen werden. Gibt es eine einfachere Möglichkeit den Inhalt eines Record in einen anderen zu kopieren als jede einzelne Variable oder Struktur einzeln?
function MyList.CopyToNewItem( Index:Integer;APTest:PTest );
var FPTest : PTest; begin FPTest := PTest( Self.Items[Index] ) ATest^.s1 := FPTest^.s1; ATest^.d1 := FPTest^.d1; ATest^.i1 := FPTest^.i1; ATest^.s2 := FPTest^.s2; usw. end; Gruss DelphiFan2008 |
AW: Kopieren des Inhalt eines Record
Direktes Kopieren des Speicherauszugs (Copy, CopyMemory oder sowas) geht natürlich, fällt aber schon in deinem Fall von TTest flach: Das würde die Referenzzählung des Strings zerstören - Tödlich.
Ich habe auch nie etwas besseres gefunden. Die einzige Möglichkeit ist irgendwie halt dem Record einen Konstruktor bzw. Funktion zu bauen die als Parameter einen bereits bestehenden Record nimmt und die Daten in den neuen überträgt... |
AW: Kopieren des Inhalt eines Record
Ich frage mich immer wieder warum man sich das Leben mit Records so schwer machen kann. Eine TObjectList<TTest> ist doch sehr viel einfacher und bequemer als die ganze Pointer- und Speicherspielerei...
Aber wie dem auch sei... zur Frage:
Delphi-Quellcode:
// EDIT:
procedure TMyList.CopyToNewItem(Index: Integer; APTest: PTest);
begin APTest^ := Self.Items[Index]^; end; Beispiel:
Delphi-Quellcode:
type
PTest = ^TTest; TTest = record s1: String; d1: Double; i1: Integer; s2: String; l1: LongInt; s3: String; n1: Int64; end; TMyList = class(TList<PTest>) public procedure CopyToNewItem(Index: Integer; APTest: PTest); end; procedure TMyList.CopyToNewItem(Index: Integer; APTest: PTest); begin APTest^ := Self.Items[Index]^; end; // Test var Test: TMyList; Current: PTest; begin Test := TMyList.Create; try New(Current); Current.s1 := 'Test 1'; Test.Add(Current); New(Current); Current.s1 := 'Test 2'; Test.Add(Current); New(Current); Current.s1 := 'Nothing'; Test.CopyToNewItem(0, Current); ShowMessage(Current.s1); // ergibt Test 1 finally Test.Free; end; end; |
AW: Kopieren des Inhalt eines Record
Wäre eine TList<TTest> mit TTest als record in dem Fall nicht sogar noch einfacher? (Disclaimer: Habe kein Delphi mit Generics-Support)
|
AW: Kopieren des Inhalt eines Record
Zitat:
Deshalb wären ja Klassen auch viel sinnvoller. Nur das Kopieren ist bei Klassen nicht so einfach durch Zuweisung möglich. |
AW: Kopieren des Inhalt eines Record
Zitat:
Bei der TObjectList wird die Sache natürlich anders (aufräumen und so). Aber reden wir nicht weiter davon. Klassen sind einfach besser weil mächtiger,dafür sind Records einfacher und bla bla bla. |
AW: Kopieren des Inhalt eines Record
Zitat:
|
AW: Kopieren des Inhalt eines Record
@jaenicke,
danke für die Antworten. Frage: Wie würde denn ein alternativer Ansatz mit TObjectList<TTest> in diesem Fall aussehen. Mir fehlt die Erfahreung mit neueren Konstrukten. Arbeite noch immer vorwiegend mit Record, Pointer und den Basisklassen welche schon ab etwa Delphi3 bekannt sind und welchen Vorteil hätte ich? Gruß DelphiFan2008 |
AW: Kopieren des Inhalt eines Record
ObjectLists sind (im Gegensatz zu Records) vergleichsweise problemlos und einfach zu handhaben. Ich hab noch Delphi2007, deshlab muß ich die property Items überschreiben (brauchst du bei <TTest> nicht).
Delphi-Quellcode:
uses
.. Contnrs; type TTest = class private FD1: Double; FN1: Int64; FI1: Integer; FL1: LongInt; FS1: String; FS2: String; FS3: String; public property D1: Double read FD1 write FD1; property N1: Int64 read FN1 write FN1; property I1: Integer read FI1 write FI1; property L1: LongInt read FL1 write FL1; property S1: String read FS1 write FS1; property S2: String read FS2 write FS2; property S3: String read FS3 write FS3; procedure Clear; procedure Assign(Value: TTest); end; TTestList = class(TObjectList) private function GetItems(Index: integer): TTest; public property Items[Index: integer]: TTest read GetItems; default; end; .. { TTest } procedure TTest.Assign(Value: TTest); begin end; procedure TTest.Clear; begin end; { TTestList } function TTestList.GetItems(Index: integer): TTest; begin Result := TTest(inherited Items[Index]); end; .. var TestList: TTestList; Index: integer; begin TestList := TTestList.Create; try // Hinzufügen von Items; Index := TestList.Add(TTest.Create); TestList[Index].Clear; // Das z.B. ginge bei einem Record nicht TestList[Index].S1 := 'Hello TObjectList'; // Löschen von Items; TestList.Delete(Index); finally TestList.Free; end; end; |
AW: Kopieren des Inhalt eines Record
@Bjoerk:
Ohne Generics macht das ganze nicht so viel Sinn. ;-) Und Clear kannst du auch problemlos in einen Record einbauen... Ein komplettes Beispiel mit einigen der Möglichkeiten findest du hier. Ein Vorteil ist, dass du dich nicht selbst um die Pointer kümmern musst. Du hast einfach immer eine Referenz, also einen impliziten Pointer, und fertig. Für das Zuweisen der Werte kannst du, wenn du von TPersistent ableitest, Assign oder AssignTo überschreiben (oder du implementierst es als normale Methode neu, wenn du von TObject ableitest). Vorteil des Überschreibens von AssignTo: Es wird schon vorher geprüft, ob nil übergeben wurde und ggf. ein qualifizierter Fehler ausgelöst und wenn die falsche Klasse zugewiesen wird, brauchst du nur inherited aufrufen und es kommt auch ein qualifizierter Fehler. Du musst keine Properties verwenden, du kannst es also auch genauso schreiben wie du es bei Records hattest (die heute aber auch Properties kennen), aber die haben den Vorteil, dass die privaten Felder nicht direkt erreichbar sind und du ggf. leicht Setter oder Getter einbauen kannst. Ein wenig mehr Quelltext ist es in der Klasse oft schon, aber dafür ist die Verwendung sehr viel einfacher. In der Praxis wird die Anzahl der Verwendungen sehr viel höher sein als die einmalige Implementierung der Klasse, so dass es sehr viel sinnvoller ist die Verwendung zu vereinfachen als bei der Implementierung der Klasse selbst zu sparen. ;-)
Delphi-Quellcode:
unit Unit15;
interface uses System.Generics.Collections, System.Classes, Vcl.Dialogs; procedure Test; implementation type TTest = class(TPersistent) private var FString1: String; FString2: String; FDouble1: Double; protected procedure AssignTo(Dest: TPersistent); override; public constructor Create(const AString1: string; const AString2: string = ''; const ADouble1: Double = 0.0); overload; constructor Create(const ACloneSource: TTest); overload; property String1: String read FString1 write FString1; property Double1: Double read FDouble1 write FDouble1; property String2: String read FString2 write FString2; end; TMyList = class(TObjectList<TTest>) public end; procedure Test; var Test: TMyList; Current: TTest; begin Test := TMyList.Create(True); try Test.Add(TTest.Create('Test 1')); Test.Add(TTest.Create('Test 2')); Test.Add(TTest.Create('Hallo')); Current := TTest.Create('Clone Source'); try Test.Add(TTest.Create(Current)); // Neues Objekt aus Current erzeugen finally Current.Free; end; for Current in Test do ShowMessage(Current.String1); // alle ausgeben // zuweisen Current := TTest.Create; try Current.Assign(Test[2]); ShowMessage(Current.String1); // Hallo finally Current.Free; end; finally Test.Free; // Die Objekte in der Liste werden durch das True für OwnsObjects im Konstruktor freigegeben end; end; { TTest } procedure TTest.AssignTo(Dest: TPersistent); var Destination: TTest; begin if Dest is TTest then begin Destination := TTest(Dest); Destination.String1 := FString1; Destination.String2 := FString2; Destination.Double1 := FDouble1; end else inherited; end; constructor TTest.Create(const AString1: string; const AString2: string = ''; const ADouble1: Double = 0.0); begin FString1 := AString1; FString2 := AString2; FDouble1 := ADouble1; end; constructor TTest.Create(const ACloneSource: TTest); begin Assign(ACloneSource); end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:24 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