Hallo!
Bei der Verwendung von Interfaces stoße ich bei einem Programm auf merkwürdige Fehler, die ich ohne das Interface nicht habe. Woran könnte das liegen?
An verschiedenen Stellen im Programm arbeite ich mit Ordnerstrukturen/Dateisystmen. Mal lese ich die Struktur direkt aus dem System, mal kommt diese aus anderen Quellen wie z.B. einer Datenbank oder einer XML-Datei. Um die Methoden für den Zugriff auf die Struktur möglichst allgemein zu halten will ich hier bei ein Interface verwenden, dass die Methoden definiert:
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:
| type IFileStructure = interface(IInterface) function FileExists(aFileName: string): boolean; function DirectoryExists(aPath: string): boolean;
function GetFileList(...): TStrings; function GetDirList(...) : TStrings; end;
TXMLFileStructure = class(TInterfacedObject, IFileStructure) private FRoot : TXMLFolderNode; ...
procedure ExplodePath(aPath: string): TStringArray; public constructor Create(XMLFilename: String);
function FileExists(aFileName: string): boolean; function DirectoryExists(aPath: string): boolean;
function GetFileList(...): TStrings; function GetDirList(...) : TStrings; end;
TFileSearcher = class(TObject) public procedure SearchFile(Filename: String; FileStructure: IFileStructure); end;
...
procedure TFileSearcher.SearchFile(Filename: String; FileStructure: IFileStructure); var dirList: TStrings; i: integer; begin dirList := FileStructure.GetDirList(...);
for i:=0 to dirList.Count do begin if (FileStructure.FileExists(dirList[i]+Filename) = true) then ... end; end; end; |
TXMLFileStructure speichert die gelesene Ordnerstruktur interne in einer Baumstruktur, die auf Zeigern und Listen basiert. Verwende ich TXMLFileStructure als "normale" Klasse (also TXMLFileStructure = class(TObject)) arbeitet diese ohne Probleme. Die Ordnerstruktur kann aus den passenden XML-Dateien ohne Fehler ausgelesen werden. Natürlich kann ich dann TXMLFileStructure nicht für TFileSearcher verwenden, aber das erstellen von TXMLFileStructure etc. gelingt fehlerfrei.
Verwende ich TXMLFileStructure jedoch als "interfaced" Klasse (also TXMLFileStructure = class(TInterfacedObject, IFileStructure)) kommt es bei der Verwendung zu Speicherzugriffsfehler. Ich ändere absolut nichts am Code von TXMLFileStructure (bis auf die Deklaration als Interfaced-Oject), trotzdem verhält sich die Klasse aufeinmal anders. Wie kann das sein?
Ich habe das Ganze bis zur folgenden Fehlerstelle zurückverfolgt:
TXMLFileStructure.ExplodePath wird intern verwendet um einen Pfad in seine Bestandteile zerlegt. Aus "C:\Test\Unterordner" wird dabei z.B. ["Test", "Unterordner"]. Intern wird hier der Ergebnis-Array für jedes Pfadstück verlängert, also "setLength(result, length(result)+1);" aufgerufen. Das funktioniert etliche Male prima, bis bei irgendeinem dieser Aufrufe aufeinmal als Nebeneffekt die interne Variable FRoot überschrieben wird und danach nicht mehr zu gebrauchen ist. Beim nächsten Zugriff auf FRoot kommt es dann zu einem Fehler.
Über die Implementierung von ExplodePath lässt sich sicherlich streiten. Aber ich kann das ganze auch Ändern und z.B. statt einem StringArray eine StringList zurück geben. Oder das Array nicht in jedem Schritt um 1 vergrößern sondern direkt die richtige Größe setzen. Wie die Methode arbeitet ist ganz egal. Irgendwann kommt es dem Effekt, dass FRoot überschrieben wird.
Das ist mir vollkommen unerklärlich. Natürlich kann wildes Schreiben in irgendwelche Arrays zu Problemen im Speicher führen, aber dazu kann "setLength(result, length(result)+1);" wohl kaum gezählt werden. Das sollte doch eigentlich "sicher" sein. Zudem tritt das Problem wirklich nur dann auf, wenn TXMLFileStructure als Interface-Objekt deklariert ist und es sonst absolut keinen Unterschied gibt.
Auch wenn ich ExplodePath gar nicht verwende kommt es irgendwo anders zu einem Fehler. Es scheint also irgendein tieferliegendes Problem zu geben.
Gibt es hierfür eine Erklärung? Muss bei der Arbeit mit Interfaces irgendwas besonders beachtet werden?
Besten Dank
Ares
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Di 26.01.2010 um 13:37