Autor Beitrag
drstar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Di 21.11.17 19:00 
So, neues Problem, es nimmt kein Ende. Habe eine Klasse definiert, die aus Variablen und einer Property besteht, siehe folgenden Codeschnipsel:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
type TK      = class(TKlient)
       private
         function onStreamRead : TMemoryStreamExt;
         procedure onStreamWrite(MemStream: TMemoryStreamExt);
       public
         constructor create;
         property MemStream : TMemoryStreamExt read OnStreamRead write onStreamWrite;
       end;

procedure TK.onStreamWrite(MemStream: TMemoryStreamExt);
var LocalStream: TMemoryStreamExt;
begin
  LocalStream := TMemoryStreamExt.Create;
  LocalStream.Read(self.Status, SizeOf(self.Status));
  LocalStream.Read(self.Index, SizeOf(self.Index));
  MemStream.CopyFrom(LocalStream, LocalStream.Size);
  LocalStream.Free;
end;

function  TK.onStreamRead: TMemoryStreamExt; //Erzeugen des Streams
const z: integer = 1;
var size: integer;
    LocalStream: TMemoryStreamExt;
begin
  LocalStream := TMemoryStreamExt.create;
  LocalStream.Write(z, SizeOf(z));  //Objekttyp
  LocalStream.Write(z, SizeOf(z));  //Größe - fürs Einlesen wichtig
  LocalStream.Write(self.Status, SizeOf(self.Status));
  LocalStream.Write(self.Index, SizeOf(self.Index));
// weitere Variablen in den Stream schmeißen
  LocalStream.Position := 4//Schreiben der Größe des Streams
  Size := LocalStream.size;
  LocalStream.write(Size, SizeOf(Size));
  Result.CopyFrom(LocalStream, LocalStream.Size);//  <--Hier kracht es
  MemStream.copyfrom(LocalStream, LocalStream.Size);//  <--kracht genauso
  LocalStream.free;
end;

constructor TK.create;
begin
  inherited;
  MemStream := TMemoryStreamExt.Create;
end;


Versuche ich den MemStream auszulesen (über onStreamRead als Getter) hagelt es eine Exception - versuche ich direkt MemStream zu befüllen ohne Umweg über LocalStream, hagelt es einen Stackoverflow. Wo liegt mein Denkfehler? TMemoryStreamExt ist aus TMemoryStream abgeleitet und um ReadString und WriteString ergänzt worden, sonst ein normaler TMemoryStream.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Di 21.11.17 19:33 
Guten Tag drstar,

du musst eine private (Feld-)Variable hinterlegen, aus der du liest und in die du schreibst.
Eine lokale Variable innerhalb der Getter/Setter - Methode kann von der jeweilig anderen Methode nicht so einfach gelesen/gesetzt werden.

Außerdem: Soll das eine Eigenschaft sein, oder viel mehr ein Ereignis?

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
drstar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Di 21.11.17 19:46 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:


Außerdem: Soll das eine Eigenschaft sein, oder viel mehr ein Ereignis?


In gewisser Weise ein Ereignis. Hintergrund ist ganz banal: Ich lese Daten aus einem FileStream ein, und befülle damit die MemoryStreams der Klassen. Die zerlegen dann ihrerseits die MemoryStreams und befüllen damit ihre Variablen. Damit das Ganze wieder gespeichert werden kann, sollen sie dann ihrerseits aus den Variablen den MemoryStream befüllen, damit die dann wieder in einem FileStream landen können.

Verstehe ich Dich dahingehend richtig, daß es nicht möglich ist, MemStream in Form einer Klasse als Variable herhalten zu lassen?
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Di 21.11.17 20:15 
Der TMemoryStream kann ebenso über die Methode .LoadFromFile() jene Datei auslesen. Dazu benötigst du keinen TFileStream an sich, außer die Datei benötigt gewisse Lese/Schreibrechte, je nachdem was du damit vorhast.
Was du hier machst, ist einfaches Kopieren von A nach B auf eine etwas unelegante Weise. :D

Was die Eigenschaft an sich betrifft, dürfte es so aussehen, um der Frage nach der Variable nachzugehen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
type
  TKlientEx = class(TKlient)
  private
    FStream: TMemoryStream;
    //function GetStream: TMemoryStream;
    //procedure SetStream(Value: TMemoryStream);
  public
    constructor Create;
    destructor Destroy; override;
    property MemStream: TMemoryStream read FStream write FStream;
    //property MemStream: TMemoryStream read GetStream write SetStream;
    //property MemStream: TMemoryStream read FStream write SetStream;
  end;

constructor TKlientEx.Create;
begin
  inherited;
  FStream := TMemoryStream.Create;
  FStream.Position := 0// Startposition des Streams
end;

destructor TKlientEx.Destroy;
begin
  FStream.Free;
  inherited;
end;

//function TKlientEx.GetStream: TMemoryStream;
//begin
//  result := FStream;
//end;

//procedure TKlientEx.SetStream(Value: TMemoryStream);
//begin
//  // ... weiterer Ablauf
//  FStream := Value;
//  // ... weiterer Ablauf
//end;

Die auskommentierten Fragmente sind eine "Alternative".

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
drstar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Mi 22.11.17 19:09 
wie es scheint, sind die auskommentierten Fragmente wohl die Lösung, nicht eine Alternative. Grund ist, daß FMemStream erst beim lesenden Zugriff von der Klasse selbst befüllt werden soll, um es dann zurückzuliefern. FMemStream wird demnach also nicht permanent aktuell gehalten, sondern erst beim Zugriff mit Daten befüllt. Allerdings kämpfe ich im Moment nun mit einem Problem an anderer Stelle, sodaß ich es noch nicht erfolgreich testen konnte.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Mi 22.11.17 20:10 
Die Getter und Setter Methoden machen hier nichts anderes, als aus der Variable FStream zu lesen:

ausblenden Delphi-Quelltext
1:
result := FStream;					

oder in sie zu schreiben:

ausblenden Delphi-Quelltext
1:
FStream := Value;					

Daher kann es einen Unterschied zu:

ausblenden Delphi-Quelltext
1:
2:
3:
property MemStream: TMemoryStream read FStream write FStream;
property MemStream: TMemoryStream read GetStream write SetStream;
property MemStream: TMemoryStream read FStream write SetStream;

nicht geben

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
drstar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Mi 22.11.17 21:28 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Die Getter und Setter Methoden machen hier nichts anderes, als aus der Variable FStream zu lesen:

ausblenden Delphi-Quelltext
1:
result := FStream;					

oder in sie zu schreiben:

ausblenden Delphi-Quelltext
1:
FStream := Value;					


Doch, sie machen mehr. Die Get-Methode (OnRead) befüllt den MemoryStream erst, denn er bleibt leer, bis auf ihn zugegriffen wird. Ohne die Get-Methode käme demzufolge ein leerer Stream zurück. Wie schon oben geschrieben, die Klasse befüllt den Stream nicht permanent, sondern nur, wenn er benötigt wird, indem auf ihn zugegriffen wird, ich habe bewußt auf eine dauerhafte Aktualisierung verzichtet.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

Daher kann es einen Unterschied zu:

ausblenden Delphi-Quelltext
1:
2:
3:
property MemStream: TMemoryStream read FStream write FStream;
property MemStream: TMemoryStream read GetStream write SetStream;
property MemStream: TMemoryStream read FStream write SetStream;

nicht geben


Eben deshalb müßte es also doch einen Unterschied machen, die Methoden sind zwingend, ein einfaches Auslesen tut es eben nicht.

So, mein neues Problem ist aber doch ein Problem - beim Auslesen des Streams mit

ausblenden Delphi-Quelltext
1:
Stream.copyfrom(K.MemStream, SizeOf(K.MemStream))					


erhalte ich einen Stream-Lesefehler, K ist eine Instanz von TK (s. o.). Wie komme ich an den Stream ran?
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 23.11.17 07:17 
Wenn du mein Beispiel so übernimmst, wirst du feststellen, dass es weder Probleme beim Lesen und Schreiben des Streams gibt, noch dass der Stream nach dem (Ein-)Lesen einer Datei leer ist:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
  klient: TKlientEx;
begin
  klient := TKlientEx.Create;
  try
    klient.MemStream.LoadFromFile('D:\Test.txt');
    ShowMessage(IntToStr(klient.MemStream.Size));
    klient.MemStream.SaveToFile('D:\Test2.txt');
  finally
    klient.Free;
  end;
end;

Zu deiner Klasse:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
type TK      = class(TKlient)
       private
         function onStreamRead : TMemoryStreamExt;
         procedure onStreamWrite(MemStream: TMemoryStreamExt);
       public
         property MemStream : TMemoryStreamExt read OnStreamRead write onStreamWrite;
       end;

function  TK.onStreamRead: TMemoryStreamExt; //Erzeugen des Streams
const z: integer = 1;
var size: integer;
    LocalStream: TMemoryStreamExt;
begin
  LocalStream := TMemoryStreamExt.create;
  LocalStream.Write(z, SizeOf(z));
  // ...
end;

procedure TK.onStreamWrite(MemStream: TMemoryStreamExt);
var LocalStream: TMemoryStreamExt;
begin
  LocalStream := TMemoryStreamExt.Create;
  LocalStream.Read(self.Status, SizeOf(self.Status));
  // ...
end;

Fällt dir da etwas auf?
Und was genau ist self.Status?

Zitat:
So, mein neues Problem ist aber doch ein Problem - beim Auslesen des Streams mit

ausblenden Delphi-Quelltext
1:
Stream.copyfrom(K.MemStream, SizeOf(K.MemStream))					


erhalte ich einen Stream-Lesefehler, K ist eine Instanz von TK (s. o.). Wie komme ich an den Stream ran?

Hier wird nichts ausgelesen, sondern von MemStream nach Stream kopiert.
Stream sollte vorher eine (Start-)Position zugewiesen bekommen.

Ich glaube nicht einmal, dass du hier eine Eigenschaft brauchst. Eine einfache Methode hätte es auch getan. Jedoch weiss ich nicht viel über dein Anliegen.


Bitte gewöhn' es dir an, Getter-Methoden mit dem Prefix "Get" zu hinterlegen, sowie Setter-Methoden mit "Set".
Das "On" kündigt ein Ereignis an, und das führt sicherlich zu Missverständnissen, wenn ein Fremder deinen Code liest.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
drstar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Do 23.11.17 10:17 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

[...]
Und was genau ist self.Status?


Status, Index, Name etc. sind Variablen, die die Klasse TKlientExt aus TKlient geerbt hat.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

Zitat:
So, mein neues Problem ist aber doch ein Problem - beim Auslesen des Streams mit

ausblenden Delphi-Quelltext
1:
Stream.copyfrom(K.MemStream, SizeOf(K.MemStream))					


erhalte ich einen Stream-Lesefehler, K ist eine Instanz von TK (s. o.). Wie komme ich an den Stream ran?

Hier wird nichts ausgelesen, sondern von MemStream nach Stream kopiert.
Stream sollte vorher eine (Start-)Position zugewiesen bekommen.


Stream hat ja eine Position. Es geht ja gerade darum, daß Stream sich den Inhalt aus den MemStreams der Klassen einsammelt und dann den ganzen Batzen in eine Datei schmeißt (bzw. umgekehrt aus der Datei liest und die MemStreams der Klassen damit füttert, die sich dann aus den MemStreams ihre benötigten Daten ziehen). Daher bringt es mir nichts, wenn die Klassen direkt in eine Datei schreiben, das soll ja der Hauptstream erledigen. Daher muß ich ja den Inhalt der MemStreams irgendwie in den Hauptstream bekommen. Ich dachte, mit der Read-Methode klappt es, klappt aber scheinbar nicht.

user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:

Bitte gewöhn' es dir an, Getter-Methoden mit dem Prefix "Get" zu hinterlegen, sowie Setter-Methoden mit "Set".
Das "On" kündigt ein Ereignis an, und das führt sicherlich zu Missverständnissen, wenn ein Fremder deinen Code liest.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Do 23.11.17 13:34 
Zitat:
Status, Index, Name etc. sind Variablen, die die Klasse TKlientExt aus TKlient geerbt hat.

Wenn jene Attribute veröffentlcht wurden, dann sollten sie keine Variablen sondern Eigenschaften sein.
Geht es dir darum, die Werte zusammen zu fassen, in einen Stream zu laden, den Stream in einer Datei abzuspeichern und wieder retour zu auszulesen?

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
drstar Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 78
Erhaltene Danke: 2

Windows 8.1/x64
Delphi 10.1
BeitragVerfasst: Do 23.11.17 22:15 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
Zitat:
Status, Index, Name etc. sind Variablen, die die Klasse TKlientExt aus TKlient geerbt hat.

Wenn jene Attribute veröffentlcht wurden, dann sollten sie keine Variablen sondern Eigenschaften sein.
Geht es dir darum, die Werte zusammen zu fassen, in einen Stream zu laden, den Stream in einer Datei abzuspeichern und wieder retour zu auszulesen?


Ja, genau darum geht es mir. Aber ich will nicht den Aufwand betreiben, bei jeder Änderung einer Variablen den Stream neu zu erzeugen, sondern nur, wenn ein Zugriff auf diesen stattfindet. Daher sind es Variablen und keine Eigenschaften.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2274
Erhaltene Danke: 419

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Fr 24.11.17 08:42 
Dann benötigst du keine Stream-Eigenschaft sondern jeweils eine Laden und Speichern Methode. Da hier nur Zeichen verarbeitet werden, kann man es sich mit einer TStringList sehr einfach machen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
type
  TKlient = class  // Kurzfassung
  private
    FStatus: Integer;
    FName: string;
  public
    property Status: Integer read FStatus write FStatus;
    property Name: string read FName write FName;
  end;

  TKlientEx = class(TKlient)
  private
    FList: TStrings;
  public
    constructor Create;
    destructor Destroy; override;
    procedure SaveAttributes(const AFileName: string);
    procedure LoadAttributes(const AFileName: string);
  end;

// ...

constructor TKlientEx.Create;
begin
  inherited;
  FList := TStringList.Create;
end;

destructor TKlientEx.Destroy;
begin
  FList.Free;
  inherited;
end;

procedure TKlientEx.SaveAttributes(const AFileName: string);
begin
  if not DirectoryExists(ExtractFileDir(AFileName)) then
    raise Exception.Create('Cannot save attributes. Directory not found.');
  
  FList.Clear;
  FList.Add(self.Name);
  FList.Add(IntToStr(self.Status));
  FList.SaveToFile(AFileName);
end;

procedure TKlientEx.LoadAttributes(const AFileName: string);
begin
  if not FileExists(AFileName) then
    raise Exception.Create('Cannot load attributes. File not found.');
  
  FList.Clear;
  FList.LoadFromFile(AFileName);
  self.Name := FList[0];
  self.Status := StrToIntDef(FList[1], 0);
end;

Aufrufen könnte man es so:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
// Speichern
var
  klient: TKlientEx;
begin
  klient := TKlientEx.Create;
  try
    klient.Status := 101;
    klient.Name := 'klient1';
    klient.SaveAttributes('D:\KlientTest.txt');
  finally
    klient.Free;
  end;
end;

// Laden
var
  klient: TKlientEx;
begin
  klient := TKlientEx.Create;
  try
    klient.LoadAttributes('D:\KlientTest.txt');
    ShowMessageFmt('Name: %s%sStatus: %d', [klient.Name, #13, klient.Status]);
  finally
    klient.Free;
  end;
end;

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)