![]() |
Gleiche Procedure mit unterschiedlichen ParameterTypen
Hallo! Ich brauche mal Hilfe:
Ich habe in einer kleinen Verwaltungssoftware ein Problem. Ich habe zwei File of Records (File of TCustomer & File of TJob) und diese sollen zu Beginn des Programms in verschiedene Arrays (Array of TCustomer & Array of TJob) eingelesen werden. Dabei enthält eine Datei die Kunden und die andere die Termine. Ich würde gerne eine Procedure haben die diese beiden Dateien in die beiden Arrays liest OHNE diese blöde Wiederholung des Quelltextes, wie unten zu sehen. Es ist ja alles genau zweimal vorhanden. Das finde ich äußerst unvorteilhaft. Am liebsten hätte ich eine Procedure, der ich den Dateinamen und das Array übergebe, in das die Datei geschreiben werden soll. Aber da die jeweiligen Datei und Arraytypen unterschiedlich sind (TJob / TCustomer) bekomme ich das nicht hin! Eine überladene Procedure würde ja zwar vom Aufruf her genau das bewirken, aber dann hab ich den Code trotzdem zweimal! :wall: Hätte da jemand ne Lösung? Ich komm einfach nicht drauf.... DANKE!!!
Delphi-Quellcode:
procedure TFrmMain.ReadFileToArray();
var i : LongInt; begin assignfile(CustomerFile, 'Customer.dat'); if fileExists('Customer.dat') then begin Reset(CustomerFile); i := 0; while not EOF(CustomerFile) do begin setlength(Customer, i + 1); Seek(CustomerFile, i); read(CustomerFile, Customer[i]); inc(i); end; CloseFile(CustomerFile); end else begin setlength(Customer, 0); end; //Und jetzt genau das gleiche mit TJob assignfile(JobFile, 'Job.dat'); if fileExists('Job.dat') then begin Reset(JobFile); i := 0; while not EOF(JobFile) do begin setlength(Job, i + 1); Seek(JobFile, i); read(JobFile, Jobr[i]); inc(i); end; CloseFile(JobFile); end else begin setlength(Job, 0); end; end; |
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Hab schon lange nichts mehr in Delphi gemacht, aber meine spontane Idee wäre, ob es nicht eine gemeinsame Oberklasse (TArray???) gibt?
|
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Hab ich leider nicht gefunden. Aber soweit ich weiß, gibt es auch keine Oberklasse TFile. die bräuchte ich dann ja auch, wenn ich dich richtig verstanden habe.
Edit: Jetzt habe ich schonwieder das gleiche Problem an einer anderen Stelle: Ich will eine Procedure die ein element eines der Arrays löscht. Dazu muss ich das array als var Parameter übergeben. Aber die Arrays sind unterschiedlich deklariert! Deswegen geht das auch wieder nicht! :wall: :wall: :wall: HILFE! :( |
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Zitat:
Nimm den Kerncode (ResetFile bis CloseFile) und schreibe ihn nur einmal generisch auf - für das Auslesen des spezifischen Records benutze eine Callback-Funktion welche vom Kerncode aufgerufen wird. Zum zweiten Problem ist die Lösung analog. Hilfreich könnte sich erweisen, daß ein Array ein kontinuierlicher Speicherbereich ist und man ein Array of Struct wie ein Pointer auf Struct ansprechen kann ... so kann das Füllen komplett unabhängig von Struct geschehen. Unter C++ gäbe es dann noch template-Funktionen *g* |
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Danke für deine Antwort: Aber ich da ein paar fragen :roteyes:
Zum ersten Problem: Nimm den Kerncode (ResetFile bis CloseFile) und schreibe ihn nur einmal generisch auf Was heißt generisch? Kenne den Ausdruck leider nicht. Du meinst warscheinlich "allgemein mit Variablen" oder? Aber dann brauche ich doch eine Variable die zu TJob UND zu TCustomer "kompatibel" ist. Oder hab ich das jetzt falsch verstanden? - für das Auslesen des spezifischen Records benutze eine Callback-Funktion welche vom Kerncode aufgerufen wird. Heul... Was ist eine CallBack-Funktion? Ist das um im Code zurückzuspringen? Wenn ja, wie macht man das? Ich kenne das nur mit Labels im Code. Zum zweiten Problem ist die Lösung analog. Hilfreich könnte sich erweisen, daß ein Array ein kontinuierlicher Speicherbereich ist und man ein Array of Struct wie ein Pointer auf Struct ansprechen kann ... so kann das Füllen komplett unabhängig von Struct geschehen. Unter C++ gäbe es dann noch template-Funktionen *g* Na und da verstehe ich nur noch Bahnhof. Array of Struct konnte mir die Delphi-Hilfe auch nicht erläutern. Man so ein Mist, bi ich wirklich so doof, dass ich das alles nicht verstehe? :cry: |
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Deine generische Funktion welche durch den Code geht, sieht nun zB folgendermaßen aus:
type TFNMyCallback=function(Identifier:PChar; Value:PChar);
Delphi-Quellcode:
Ist der Funktionspointer, welcher als Parameter übergeben wurde, NIL, tust du nichts. Sonst rufst du die Callbackfunktion ganz normal auf und übergibst die Daten aus Kernfunktion die du benötigst (sagen wir mal Recordgröße und Pointer zu Puffer o.ä.)
function ReadMyFile(fName:PChar; FNcallback:TFNMyCallback);
Delphi-Quellcode:
if Assigned(FNcallback) FNcallback(Identifier, Value);
Zitat:
Template-Funktionen funktioniern unabhängig vom Typ. Beispiel (Funktion welche Maximalwerte herausfindet):
Code:
Beim Aufruf tust du nun dies:
template <class T> T Max(T Wert1, T Wert2);
Code:
Wie du siehst, mußt du den Prototypen (und konsequenterweise auch den Rumpf) nur einmal schreiben und kannst ihn dann für verschiedene Typen (nicht nur, wie oben, Basistypen) nutzen. Wäre hier für dich ideal.
double d = Max<double>(d1, d2);
int i = Max<int>(i1, i2); unsigned char u = Max<unsigned char>(c1, c2); |
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Ich sitz hier jetzt schon fast ne Stunde und versuche umzusetzen was du mir geschrieben hast. Aber irgendwie ist mir der Sinn/das Ziel noch nicht 100% klar, weshalb ich nicht so richtig weiß vorauf ich hinarbeite. Das macht es für mich unmöglich deinen Vorschlag umzusetzen. Ich gebe mir echt mühe, aber ich verstehe das einfach nicht. Du hast ja schon so viel geschrieben, ich mag dich garnicht mehr fragen: Aber würdest du mir den gefallen tuen und mir ein kleines Beispiel in Delphi programmieren? Denn das ist für meinen Wissensstand einfach zu abgehoben, weswegen ich das auch sehr genre lernen würde...
|
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Wenn es bis morgen Zeit hat, dann schreib mir morgen nochmal ne PN. Ich bräuchte dann auch noch die Prototypen der beiden Records (Customer, Job).
|
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Wird gemacht... Danke!
|
Re: Gleiche Procedure mit unterschiedlichen ParameterTypen
Ich hab da mal was vorbereitet. Bedienungsanleitung ist als Kommentar dabei. Habe es noch nicht getestet. Probiers mal und beschwer dich wenn es nicht funzt.
Delphi-Quellcode:
(*
Diese Funktion liest aus einer Datei mit einer beliebigen Anzahl von Records einer festen Größe (wobei die Dateigröße 2 GB nicht überschreiten darf) die Reccords in ein Array. Dabei ist für die Funktion irrelevant wieviele Records sie lesen soll oder wie die Struktur eines Records oder des Arrays ist. Die Funktion erfüllt gleichzeitig eine zweite Aufgabe: [...] xArray : array[] of TMyRecordType; begin // Get number of records in the file dwNumRecordsBefore := ReadFileIntoArray('datei.dat', Nil, 0, sizeof(TMyRecordType)); // Adapt array size SetLength(xArray, dwNumRecords); // Read into the array dwNumRecordsAfter := ReadFileIntoArray('datei.dat', @xArray, dwNumRecordsBefore, sizeof(TMyRecordType)); end; Wie man sehen kann, holt der erste Aufruf, bei dem die Anzahl zu lesender Elemente auf Null gesetzt wurde, die Anzahl von Records in der Datei. Danach wird die Arraygröße angepaßt und das Array wird ausgelesen. Wenn man will, kann man danach dwNumRecordsAfter und dwNumRecordsBefore vergleichen. ACHTUNG: Diese Funktion checkt nicht, ob die Dateigröße ein ganzzahliges Vielfaches der Recordgröße ist, also quasi ob die Anzahl von Records exakt paßt. Stattdessen wird die maximale Anzahl von Records ermittelt, die in eine Datei der entsprechenden Größe passen würden. *) function ReadFileIntoArray( // Holds the filename of the file to read sFileName: string; // Pointer to the first element of a sized array lpArray: Pointer; // Number of elements to read // --> if this is 0 the function returns the number of records in the file dwNumToRead:DWORD; // Size of a single record in the file - MUST NOT be zero!!! dwSizeOfElement: DWORD // Return number of elements read ): DWORD; var hFile: THandle; // Handle to the file to read i, // Loop counter dwRead, // Holds the number of read bytes dwNumrecords: DWORD; // Holds the number of records to read lpBuffer:Pointer; // Intermediate pointer - holds current offset inside array bError:Boolean; begin Result := 0; bError := False; // Open file read-only hFile := CreateFile(@sFileName[1], GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); // If successfully opened if hFile <> INVALID_HANDLE_VALUE then try // Check filesize, get number of records to read! dwNumRecords := GetFileSize(hFile, nil); // Only read if the function succeeds if dwNumRecords <> INVALID_FILE_SIZE then begin // Calculate the number of elements to read ... dwNumRecords := dwNumRecords div dwSizeOfElement; // If the array pointer is not assigned ... if dwNumToRead = 0 then begin // Return maximum number of records in the file Result := dwNumRecords; Exit; end; // If the array buffer is NIL if not Assigned(lpArray) then Exit; // Adjust number of records to read in case the caller wants less records than are in the file if dwNumToRead < dwNumRecords then dwNumRecords := dwNumToRead; // Read the calculated number of records for i := 0 to dwNumRecords - 1 do begin // Calculate the offset at which to read lpBuffer := Pointer(DWORD(lpArray) + i * dwSizeOfElement); // Read the record into the buffer bError := not ReadFile(hFile, lpBuffer, dwSizeOfElement, dwRead, nil); // Check for size read - if smaller than required or Error -> quit if (dwSizeOfElement <> dwRead) or bError then begin // Fill buffer with zeroes ... - maybe obsolete ZeroMemory(lpBuffer, dwSizeOfElement); // Upon failure quit here Break; end; // Set the number of successfully read records Result := i; end; end; finally // Close file CloseHandle(hFile); end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:10 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