TStringlist als functions Ergebnis

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

TStringlist als functions Ergebnis

Beitrag von DL3AD »

Hallo,
ich habe eine function die als Ergebnis ein String liefert - dass funktionier auch soweit - aber ich benötige als Ergebnis eine TStringlist.

Code: Alles auswählen

//USB Geräteliste abrufen
function USBlist(ip:string):string;
var
  AProcess: TProcess;
  Mylist: TStringList;
begin
  Mylist:= TStringList.Create;
  AProcess:= TProcess.Create(nil);
  AProcess.Options:= [poWaitOnExit, poUsePipes];
  AProcess.Executable:= 'usbip';
  AProcess.Parameters.Add('list');
  AProcess.Parameters.Add('-r');
  AProcess.Parameters.Add(ip);
  Aprocess.Execute;
  Mylist.LoadFromStream(Aprocess.Output);
  USBlist:= Mylist.Text;
  AProcess.Free;
  Mylist.Free;
end;                        
Abruf der Liste geht hiermit

Code: Alles auswählen

//USB Liste
procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Append(USBlist('192.168.2.224'));
end;         
Nun möchte ich aber folgendes machen

Code: Alles auswählen

function USBlist(ip:string):TStringlist;
var
  AProcess: TProcess;
begin
  AProcess:= TProcess.Create(nil);
  AProcess.Options:= [poWaitOnExit, poUsePipes];
  AProcess.Executable:= 'usbip';
  AProcess.Parameters.Add('list');
  AProcess.Parameters.Add('-r');
  AProcess.Parameters.Add(ip);
  Aprocess.Execute;
  Result.LoadFromStream(Aprocess.Output);
  AProcess.Free;
end;                     
Wie baue ich nun die function ein um create und aufuzrufen zu gestalten ?

Code: Alles auswählen

//USB Liste
procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Append(USBlist('192.168.2.224').text);
end;                                             
Gruß Frank

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: TStringlist als functions Ergebnis

Beitrag von MmVisual »

Probiere das mal:

Code: Alles auswählen

Procedure USBlist(ip:string; Var sl: TStrings);
var
  AProcess: TProcess;
begin
  AProcess:= TProcess.Create(nil);
  AProcess.Options:= [poWaitOnExit, poUsePipes];
  AProcess.Executable:= 'usbip';
  AProcess.Parameters.Add('list');
  AProcess.Parameters.Add('-r');
  AProcess.Parameters.Add(ip);
  Aprocess.Execute;
  sl.LoadFromStream(Aprocess.Output);
  AProcess.Free;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  USBlist('192.168.2.224', Memo1.Lines);
end;
EleLa - Elektronik Lagerverwaltung - www.elela.de

wp_xyz
Beiträge: 5142
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist als functions Ergebnis

Beitrag von wp_xyz »

Du kannst natürlich Result direkt in der USBList-Funktion erzeugen:

Code: Alles auswählen

function USBlist(ip:string):TStrings;  // Wegen der allgemeineren Verwendbarkeit würde ich den Ergebnistyp "TStrings" verwenden, statt "TStringList"
var
  AProcess: TProcess;
begin
  Result := TStringList.Create;
  ... // Rest wie bisher, Result darf hier NICHT freigegeben werden, sondern nur im aufrufenden Code
Ich hasse solche Konstruktionen (obwohl ich sie selbst schon mehrfach genauso gemacht habe), denn sie verleiten zu genau dieser Anwendung, die du vorhast. Das Problem ist, dass in der Funktion ein Constructor versteckt ist, und es in exakt diesem Anwendungsfall keine Möglichkeit gibt, den entsprechenden Destructor aufzurufen - möglicherweise wird überhaupt nicht klar, dass das nötig ist. Denn TStringList ist kein referenzgezählter Typ, so wie String, der sich selbst zerstört, wenn nicht mehr benötigt.

Du kannst aus dem Einzeiler einen Dreizeiler machen

Code: Alles auswählen

var
  list: TStringList;
begin
  list := USBList('192.168.2.224');
  try
    Memo1.Append(list);
  finally
    list.Free;
  end;
Oder - was ich schöner finde, weil in der aufrufenden Funktion das magische Wort "Create" erscheint, so dass man weiß, dass irgendwo auch ein "Free" stehen muss:

Code: Alles auswählen

procedure USBList(AList: TStrings);
begin
  ...  // wie bisher, nur "AList" anstatt "Result"
end;
 
procedure TForm1.Button2Click(Sender: TObject);
var
  list: TStrings;
begin
  list := TStringList.Create;
  try
    USBList(list);
    Memo1.Append(list);
  finally
    list.Free;
  end;
end; 
@MmVisual: das "var" in deiner USBList-Prozedur ist m.E. genaugenommen falsch, da dort keine TStrings-Liste neu erzeugt wird. Sondern die Funktion verwendet die bereits existierende Instanz der Klasse und ändert etwas an ihren Eigenschaften (indem Strings hinzugefügt werden). Der Pointer auf die Instanz bleibt dagegen unverändert, deshalb könnte man auch das noch striktere "const" verwenden.

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: TStringlist als functions Ergebnis

Beitrag von DL3AD »

Danke für eure Tipps.

Habe es nun folgendermaßen gelößt - in einer Unit mit verschiedenen gesammelten Funktionalitäten ist nun folgende procedure enthalten

Code: Alles auswählen

//USB Geräteliste abrufen
procedure USBlist(ip:string;sl:TStringlist);
var
  AProcess: TProcess;
begin
  AProcess:= TProcess.Create(nil);
  AProcess.Options:= [poWaitOnExit, poUsePipes];
  AProcess.Executable:= 'usbip';
  AProcess.Parameters.Add('list');
  AProcess.Parameters.Add('-r');
  AProcess.Parameters.Add(ip);
  Aprocess.Execute;
  sl.LoadFromStream(Aprocess.Output);
  AProcess.Free;
end;                         
der Aufruf defolgt dann folgendermaßen

Code: Alles auswählen

//USB Liste aufrufen
procedure TForm1.Button2Click(Sender: TObject);
var
  sl1: TStringlist;
begin
  sl1:= TStringlist.Create;
  USBlist('192.168.2.224', sl1);
  Memo1.Append(sl1.Text);
  sl1.Free;
end;          
Somit bin ich sauber mit Create und Free

Gruß Frank

wp_xyz
Beiträge: 5142
Registriert: Fr 8. Apr 2011, 09:01

Re: TStringlist als functions Ergebnis

Beitrag von wp_xyz »

DL3AD hat geschrieben: Somit bin ich sauber mit Create und Free
"Nicht nur sauber, sondern rein" bist du, wenn du jeder Resourcen-Anforderung einen try-except Block spendierst, damit die Resource auch beim Auftreten einer Exception wieder freigegeben wird:
z.B.

Code: Alles auswählen

procedure TForm1.Button2Click(Sender: TObject);
var
  sl1: TStringlist;   // Warum eigentlich die "1"?
begin
  sl1:= TStringlist.Create;
  try
    USBlist('192.168.2.224', sl1);
    Memo1.Append(sl1.Text);
  finally
    sl1.Free;
  end;
end;

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: TStringlist als functions Ergebnis

Beitrag von DL3AD »

...ich liebe dieses Forum - weil man fast immer eine fachlich fundierte Antwort bekommt DANKE :D
Das pflege ich noch ein - will erstmal die Grundfunktionalitäten erstellen.

USB Geräte auf einem Raspi zu einem Debianrechner übers Netzwerk zu Tunneln ist schon eine feine Sache - leider ist das USBIP Paket sehr rudinenrär - also bastel ich etwas dazu.

Gruß Frank

Antworten