Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Stringlisten in mehreren Prozeduren nutzen (https://www.delphipraxis.net/98227-stringlisten-mehreren-prozeduren-nutzen.html)

WIng2005 23. Aug 2007 14:14


Stringlisten in mehreren Prozeduren nutzen
 
Hallo,

wenn ich wie folgt Stringlisten nutze, bekomme ich eine
Zugriffsverletzung:

Delphi-Quellcode:

var sl:TStringlist;


Procedure A;
Begin
SL := TStringList.Create;
SL('Text ; Text');

b;
c;
end;



Procedure b;
Begin
SL.Add('Text ; Text');      //<-Exception
end;

Procedure c;
Begin
SL.SaveToFile('datei.csv');
end;
Muss die Stringlist nach jedem Schreiben geschlossen werden? Wenn ja, wie hänge ich an?

MFG
Steffen

s-off 23. Aug 2007 14:19

Re: Stringlisten in mehreren Prozeduren nutzen
 
Hallo,

die Stringliste ist nur dort gültig, wo Du sie erzeugst.

Du solltest sie also global erzeugen.

Edit:
Schwachsinn - ich meine natürlich, dass sie nur dort gültig ist, wo Du sie deklarierst.

Edit2:
Zitat:

Zitat von WIng2005
Muss die Stringlist nach jedem Schreiben geschlossen werden? Wenn ja, wie hänge ich an?

Nein.

Allgemein:
Wenn Du eine Stringliste in allen Methoden einer Klasse benutzen möchtest, dann solltest Du sie auch in der Klasse deklarieren.
Am Beispiel einer Klasse TForm1 sieht das dann ungefähr so aus:

Delphi-Quellcode:
Unit Unit1;

Interface

Uses
   Windows,
   Messages,
   SysUtils,
   Variants,
   Classes,
   Graphics,
   Controls,
   Forms,
   Dialogs;

Type
   TForm1 = Class(TForm)
      Procedure FormCreate(Sender: TObject);
      Procedure FormDestroy(Sender: TObject);
   private
      sl: TStringlist;
   End;

Var
   Form1: TForm1;

Implementation

{$R *.dfm}

Procedure TForm1.FormCreate(Sender: TObject);
Begin
   sl := TStringlist.Create;
End;

Procedure TForm1.FormDestroy(Sender: TObject);
Begin
   FreeAndNil(sl);
End;

End.
Du könntest dann auf 'sl' in allen Methoden Deiner Klasse 'TForm1' zugreifen.
Willst Du auch in klassenfremden Methoden auf sl zugreifen, so musst Du die Sichtbarkeit erhöhen, oder eine Property mit entsprechenden read/write-Methoden zur Verfügung stellen, oder die Stringliste global deklarieren.

Edit3:
Rechtschreibfehler in Edit2 behoben :mrgreen:

DeddyH 23. Aug 2007 14:35

Re: Stringlisten in mehreren Prozeduren nutzen
 
Ich kann das Problem nicht nachvollziehen :gruebel:
Hier mal eine Testunit:
Delphi-Quellcode:
unit UnitNix;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private-Deklarationen }
    sl: TStringList;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  sl := TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Assigned(sl) then
    FreeAndNil(sl);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Assigned(sl) then
    begin
      sl.Add('eine Zeile');
      Button2Click(self);
      Button3Click(self);
    end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if Assigned(sl) then
    sl.Add('eine weitere Zeile');
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  if Assigned(sl) then
    sl.SaveToFile('C:\blablubb.txt');
end;

end.

RavenIV 23. Aug 2007 15:16

Re: Stringlisten in mehreren Prozeduren nutzen
 
Das sollte so aber funktionieren...

s-off 23. Aug 2007 15:22

Re: Stringlisten in mehreren Prozeduren nutzen
 
Vielleicht hat er seine Variable in einer Klasse deklariert. Lt. seines Quelltextes sieht es zwar nach einer globalen Deklaration aus, aber vielleicht ist das einfach nur ein Copy&Paste-Fehler...

DeddyH 23. Aug 2007 15:24

Re: Stringlisten in mehreren Prozeduren nutzen
 
Somit fischen wir mal wieder im Trüben.

RavenIV 23. Aug 2007 15:27

Re: Stringlisten in mehreren Prozeduren nutzen
 
Vielleicht kommt der Fehler auch daher:
Delphi-Quellcode:
Button2Click(self);
Button3Click(self);
Das self bezieht sich nämlich auf das Form und nicht auf den Button1.
Besser wäre vermutlich:
Delphi-Quellcode:
Button2Click(Sender);
Button3Click(Sender);

DeddyH 23. Aug 2007 15:37

Re: Stringlisten in mehreren Prozeduren nutzen
 
Moment, bei mir kommt kein Fehler, nicht verwechseln ;)

s-off 23. Aug 2007 15:48

Re: Stringlisten in mehreren Prozeduren nutzen
 
Zitat:

Zitat von DeddyH
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if Assigned(sl) then
    FreeAndNil(sl);
end;

Was bezweckst Du in dem Fall eigentlich mit dem 'Assigned'?

Edit: Delphi-Tag geöffnet

mkinzler 23. Aug 2007 15:49

Re: Stringlisten in mehreren Prozeduren nutzen
 
Er fragt ab, ob die Variable ein Objekt referenziert

s-off 23. Aug 2007 15:52

Re: Stringlisten in mehreren Prozeduren nutzen
 
Zitat:

Zitat von mkinzler
Er fragt ab, ob die Variable ein Objekt referenziert

'Assigned' kann aber keine ungültigen oder nicht initialisieren Zeiger 'aufspüren' - somit liesse sich ein Laufzeitfehler bei nicht vorhandenem Objekt so nicht verhindern.

mkinzler 23. Aug 2007 15:54

Re: Stringlisten in mehreren Prozeduren nutzen
 
Es prüft nur auf Nil. wenn das Objekt bereits zerstört ist, liefert .Assigned natürlich true. deshalb ist es ja sinnvoll FreeAndNil zu verwenden

s-off 23. Aug 2007 15:58

Re: Stringlisten in mehreren Prozeduren nutzen
 
Ja, das ist mir schon klar.

Aber Du stimmst mir doch sicherlich zu, dass das Assigned an dieser Stelle überflüssig ist, da ein einfaches FreeAndNil(sl) ausreichen würde, oder?

Bin gerade etwas verwirrt.

RavenIV 23. Aug 2007 15:59

Re: Stringlisten in mehreren Prozeduren nutzen
 
Kommt wieder zurück zum eigentlichen Thema...

mkinzler 23. Aug 2007 16:00

Re: Stringlisten in mehreren Prozeduren nutzen
 
Doppelt hält halt besser :)

s-off 23. Aug 2007 16:02

Re: Stringlisten in mehreren Prozeduren nutzen
 
Zitat:

Zitat von RavenIV
Kommt wieder zurück zum eigentlichen Thema...

Sorry für den Schwenk Richtung OT :?

Aber ich glaube, dass wir nicht weiterkommen, solange WIng2005 nicht mal die Senftube öffnet.

WIng2005 23. Aug 2007 20:42

Re: Stringlisten in mehreren Prozeduren nutzen
 
So nun ich mal wieder....
Ich kann leider erst am Montag testen, was ihr so schreibt (Delphi habe ich leider nur an der Arbeit und ab heute
ist Wochenende :-D ).
Die Stringlist ist einfach im public-Teil der Unit deklariert. In der Prozedur, in welcher die Liste als
solche erzeugt wird, kann ich uneingeschränkt schreiben (A). Jedoch bricht die Anwendung ab, sobald ich in B versuche
selbiges zu tun. Das ist mein ganzes Problem....

MFG
Steffen

s-off 24. Aug 2007 07:05

Re: Stringlisten in mehreren Prozeduren nutzen
 
Zitat:

Zitat von WIng2005
Die Stringlist ist einfach im public-Teil der Unit deklariert.

Eine Unit ist nichts anderes als eine Datei und hat somit keinen Public-Teil in dem Sinne. Du wolltest hier sicherlich etwas schreiben wie
Zitat:

Die Stringlist ist einfach im public-Teil der Klasse deklariert.
Oder meinst Du, dass Du die Strginliste global, also ausserhalb jeglicher Klassendeklaration deklariert hast? Das sähe dann in etwa so aus:

Delphi-Quellcode:
Unit Unit1;

Interface

Uses
   Windows,
   Messages,
   SysUtils,
   Variants,
   Classes,
   Graphics,
   Controls,
   Forms,
   Dialogs;

Type
   TForm1 = Class(TForm)
   private
      { Private-Deklarationen } //<--hier private (in der Klasse TForm1)
   public
      { Public-Deklarationen } //<--hier public (in der Klasse TForm1)
   End;

Var
   Form1: TForm1;
   sl: TStringlist; //<-- hier global

Implementation

{$R *.dfm}

End.
Wir sind nun leider nicht schlauer, als wir es vor Deiner Antwort waren :wink:

Sidorion 24. Aug 2007 09:03

Re: Stringlisten in mehreren Prozeduren nutzen
 
Nur mal nebenbei: Globale Objekte sollte man über ein Singleton absichern, sprich: eine Funktion zum Zugriff deklarieren. Im Initialzation-Abschnitt wird der Zeiger auf Nil gesetzt, im finalization das Objekt zerstört und in der Funktion erstelle, falls es noch nicht erstellt wurde, also z.B. so:
Delphi-Quellcode:
Unit Foo;

Interface

Function MyStringList: TStringList;

Implementation
Var
  oMyList: TStringList;

Function MyStringList: TStringList;
Begin
  If Not Saaigned(oMyList)
  Then oMyList:=TStringList.Create;
  Result:=oMyList;
End;

...

Initialization
oMyList:=Nil;

Finalization
FreeAndNil(oMyList);

End.
Dann ist auch gewährleistet, dass diese Liste auch erstellt wird bei Benutzung. So wird allerdings die vorzeitige Zerstörung nicht verhindert, da muss man dann noch aufpassen. Solange man nur über die Funktion zugreift und den Destruktor nicht ruft, passiert nix.

s-off 24. Aug 2007 09:06

Re: Stringlisten in mehreren Prozeduren nutzen
 
Zitat:

Zitat von Sidorion
Nur mal nebenbei:[...]

Was möchtest Du jetzt?

Sidorion 24. Aug 2007 13:12

Re: Stringlisten in mehreren Prozeduren nutzen
 
Darauf hinweisen, dass einne globale Instanz gesichert werden muss, damit man sie nicht verwendet, bevor sie angelegt (.create) wurde, denn das führt zu Zugriffsverletzungen. Ausserdem sollte sowas geregelt zurückgeabut werden (Ja nach Beenden der Applikation wird der Speicher eh wieder frei, aber bei sowas kanns auf die Reihenfolge ankommen).

s-off 24. Aug 2007 13:38

Re: Stringlisten in mehreren Prozeduren nutzen
 
Ja,

das ist allgemein bekannt, dass man kein Spanferkel essen kann, bevor es geboren wurde.
Nur mit Deinem Code-Beispiel und den dazu gehörigen Erläuterungen komme ich ehrlich gesagt nicht ganz klar.

*Ratter-ratter*

Ah, ok - jetzt verstehe ich. Du greifst auf Deine Stringliste nicht direkt zu, sondern über eine Funktion, die dafür sorgt, dass die Stringliste erzeugt wird, sofern noch nicht geschehen.
Da ich in der Regel keine globalen Objekte nutze, war mir der Grund für Dein Konstrukt nicht auf Anhieb klar; sorry.

Edit:
Rechtschreibfehler eingebaut.

Sidorion 24. Aug 2007 16:27

Re: Stringlisten in mehreren Prozeduren nutzen
 
Das mit der Stringliste ist ja nur ein Trivialbeispiel.
Manchmal benötigt man solche Konstrukte, für z.B.: eine Factory, die einem Instanzen von registrierten Klassen liefert. Ist dann praktisch, wenn solche Klassen für Kundenanpassungen überschrieben werden müssen. Dann reicht es der Factory zu sagen, wenn Klasse X angefordert wird, gib eine Instanz von abgeleiteter Klasse Y zurück. Erspart viel Schreibarbeit und man kann sichergehen, dass überall die Klasse ersetzt wird. Im Projekt meiner Firma werden z.B.: die Dialoge über eine Art Scriptsyntax erstellt. Da steht halt im Script einfach der Klassenname drin.

WIng2005 26. Aug 2007 12:38

Re: Stringlisten in mehreren Prozeduren nutzen
 
Sorry, dass ich derzeit ein winig passiv war (war ein anstrengendes WE)....

@s-off:bisher habe ich es genau so gemacht, wie du im 2. Beispiel gezeigt hast. (...also ausserhalb jeglicher Klassendeklaration deklariert....). Die weiteren aufgeführten Anmerkungen, die hier angesprochen wurden, sind für mich nicht wirklich nachvollziehbar (vielleicht hätter der Titel mit "Noob braucht Hilfe..." beginnen sollen.)
Der eigentliche Grund für die Stringlisten ist, dass ich über mehrere Proceduren hinweg Informationen sammeln (Format: "Text ; Text; Text") kann, welche dann einfach in eine CSV geschrieben werden.
Diese dienen dann als "Protokoll" einer Berechnung.
Da die Infos aber in mehreren Prozeduren und Funktionen entstehen, muß ich global auf die gleiche Stringliste zugreifen können... Das ist schon alles. Schöner wäre natürlich (habe ich so aber noch nicht gesehen), wenn ich die CSV direkt beschreiben könnte. Bisher habe ich eine korrekte Spaltentrennung nur via Stringlisten hinbekommen.


MFG und danke für die zahlreichen Hinweise
Steffen

WIng2005 27. Aug 2007 10:13

Re: Stringlisten in mehreren Prozeduren nutzen
 
Das Problem hat sich geklärt. Bin alles nochmal durchgegangen und habe festgestellt, dass das erste
Schreiben in die Liste VOR dem eigentlichen Erzeugen stattfand. Dumm!

Naja, habe es entsprechend geändert...


MFG
Steffen

grenzgaenger 27. Aug 2007 22:45

Re: Stringlisten in mehreren Prozeduren nutzen
 
sag mal, warum machste es nicht so, wie in der prozeduralen progammierung...

Delphi-Quellcode:
procedure main;
var
 sl: tstringlist;
begin
 sl := tstringlist.create;
 try
  sub(sl);
 finally
  sl.free;
 end;
end;

procedure sub(const sl: tstrinlist);
begin
// mach irgendwas mit sl...
end;

WIng2005 28. Aug 2007 09:38

Re: Stringlisten in mehreren Prozeduren nutzen
 
Im Endeffekt mache ich es ja so, nur dass ich die SL nicht jedesmal übergebe, sondern (auch aus Gründen der vielen
Änderungen, die ich sonst vornehmen müßte) deklariere sie global.

MFG
Steffen


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:22 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