Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Interfaces in Delphi


theo - Mo 07.11.11 22:27
Titel: Interfaces in Delphi
Hallo,

ich möchte die Meinungen von anderen Programmiern zu folgenden Thema hören:

Was spricht für oder gegen den Ansatz:
- ALLE! Objekte über ein interface abzubilden und den Zugriff nur über interface zuerstellen -


jaenicke - Mo 07.11.11 22:57

Wenn die Performance keine Rolle spielt, mag man daran denken. Aber eine der Vorteile von Delphi ist gerade, dass es keinen integrierten Garbage Collector hat. Wenn man alle Objekte über Interfaces ansprechen würde, würde man sich die entsprechenden Nachteile mit aufhalsen.

Ich sehe aber weder einen Sinn, noch echte Vorteile darin, also warum sollte man das wollen? :gruebel:

Mit Interfaces kann man die rein baumartige Vererbung in Delphi erweitern. Und dafür sind Interfaces auch gut. Auch für einige andere Zwecke sind sie sinnvoll. Aber für alle Objekte?


Lemmy - Mo 07.11.11 23:19

also ALLE Objekte über EIN interface? ;-)

Der Vorteil von Interfaces liegt klar im Design der Anwendung. Wenn man das Fachmodell über Interfaces aufbaut kann man dieses sehr einfach über Unit-Tests überprüfen (Stichwort MOCK), ein ggf. tief geschachteltes Vererbungsmonster kann abgeflacht werden und Abhängigkeiten zwischen Klassen werden aufgebrochen (Stichwort programmieren gegen Schnittstellen und nicht gegen eine Implementierung).

Aber klar bringt das auch Nachteile mit sich. In der letzten Ekon (vor 2 Wochen) gab es dazu einen KLasse Workshop von Bern Ua und Daniel Wischnewski. Da meinte Bernd Ua sinngemäß: eine gut zu testende Anwendung hat ne schlechte Performance.


theo - Di 08.11.11 00:46

Pro Objekt ein Interface


baka0815 - Di 08.11.11 12:12

user profile icontheo hat folgendes geschrieben Zum zitierten Posting springen:
Pro Objekt ein Interface

Warum :?:


theo - Di 08.11.11 20:04

user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
user profile icontheo hat folgendes geschrieben Zum zitierten Posting springen:
Pro Objekt ein Interface

Warum :?:

Dieses "Warum" ist genau meine Frage, weil wir im Team einen Kollegen haben, der fast Alles über INTERFACES macht.

Ich persönlich bin der Meinung, dass ein wohl überlegtes Klassenmodell mehr den allgemeinem Programmierstill in Delphi entspricht. Wobei INTERFACES natürlich auch eine Berechtigung haben (z.B. XML-Datenanbindung, COM-Schnittstelle).


jaenicke - Di 08.11.11 20:56

user profile icontheo hat folgendes geschrieben Zum zitierten Posting springen:
Dieses "Warum" ist genau meine Frage, weil wir im Team einen Kollegen haben, der fast Alles über INTERFACES macht.
Wie es in dem Fall ist, kann man von außen natürlich schlecht sagen, aber positive Gründe fallen mir beim besten Willen nicht ein.

Jetzt mal abgesehen von COM oder ähnlichem, wo man nicht um Interfaces herumkommt, können Interfaces rein in Delphicode helfen, wenn man es nicht hinbekommt eine saubere Klassenkapselung zu erstellen, bei denen die Beziehungen zwischen den Klassen nur in eine Richtung gehen. Ohne Interfaces ließe sich so etwas nur durch Kreuzbezüge lösen, was aber nicht immer hinzubekommen ist, wenn man sich da zu sehr festgefahren hat. In manchen Fällen machen Interfaces dann aber durchaus Sinn.

Zudem hilft es, wenn man keine saubere Struktur hinbekommt, bei der man an definierten Stellen die Objekte auch wieder freigibt. Denn durch die Interfaces erledigt das der automatisch generierte Code des Compilers automatisch.

Aber hast du denn nicht mal gefragt was der Hintergrund ist? Ich meine er muss es doch (hoffentlich) am besten wissen warum er das so macht.


baka0815 - Mi 09.11.11 10:02

Interfaces machen nur dann Sinn, wenn man mehrere Objekte hat, die dasselbe Ziel verfolgen.

Wenn man z.B. das Laden einer Datei generalisieren möchte:
Man bekommt z.B. ein Objekt vom Typ IFile von der FileLoadFactory zurück, welches dann ein TWord, TExcel, TText, TWhatever ist.

Wenn man ein Listener-Konzept (siehe Java) umsetzen möchte:
Das Listener-Interface liefert nur die aufzurufende Methode, die Implementierung bleibt dann wem anders überlassen.

Warum man jedoch für JEDES Objekt auch ein Interface haben möchte, ist für mich so nicht ersichtlich.


delfiphan - Sa 12.11.11 01:55

In .NET/Java macht man das manchmal, um die Klassen isoliert voneinander testen zu können. Allerdings setzt das einen DI-Mechanismus voraus. DI ohne GC ist schwer zu realisieren und verkompliziert das ganze wahrscheinlich nur.

Interfaces sind in Delphi schlecht umgesetzt. Das ganze ist zu stark an COM angelehnt. Ich denke mal dafür wurde es ursprünglich entwickelt. Das ganze hat einfach noch viele Kanten und Ecken. Es gibt keine volle Unterstützung von Properties; kein voller Language-Support mit "is" und "as" sondern über "Supports"; man muss für gewisse Features Guids angeben; man muss einen anderen Programmierstil verwenden wegen der Referenzzählung; man kann trotz Referenzzählung Memory-Leaks erzeugen (Interface-Instanz weist sich einem Childobjekt zu oder zirkuläre Abhängigkeit) dagegen gibt es kein Gegenmittel wie Weak References ausser man manipuliert die Referenzzählung; früher konnte man Interfaces nicht mehr zu Objekte casten.

Für viele dieser Dinge gibt es technische Erklärungen, aber .NET hat all diese Problemchen und Einschränkungen einfach nicht...

Fazit: In Delphi ist es unüblich und ich würde davon abraten.


jaenicke - Di 29.11.11 20:30

Mittlerweile habe ich auch herausgefunden, dass z.B. Nick Hodges ein Anhänger dieser Verfahrensweise ist. Hauptzweck: Die einzelnen Codeteile voneinander entkoppeln. Mehr dazu hier im Video:
http://www.embarcadero.com/coderage/sessions
(Mittwoch: Delphi, Dependency Injection, and the Delphi Spring Framework)

Kurzfassung meiner Meinung dazu:
Die Idee dahinter ist durchaus nachvollziehbar und an sich nicht schlecht, aber ich halte das so nicht für sauberen Code. Mit irgendwelchen Generatorklassen herumwerfen, die Klassen erzeugen ohne dass man direkt sieht wo die Implementierung herkommt? Aus Versehen die falsche Unit entfernt oder hinzugefügt und plötzlich geht etwas nicht mehr, weil es keine Fehlermeldung gibt? (Weil der Compiler das nicht prüfen kann.)

Sorry, aber das ist meiner Meinung nach einfach nicht richtig durchdacht, birgt Gefahren insbesondere bei der Arbeit im Team und ist daher keine saubere Softwarearchitektur.

Die Verwendung von Interfaces um gezielt Codeteile zu entkoppeln macht an den richtigen Stellen durchaus Sinn, aber in der Form nicht. So überwiegen die Nachteile und es besteht die Gefahr, dass jemand durch Änderungen Probleme an ganz anderer Stelle verursacht und es durch das Konzept gar nicht mitbekommen kann. Eben weil man die Compilerunterstützung gezielt abkoppelt.

Wobei, um das noch einmal deutlich zu schreiben, meine Kritik jetzt speziell für den Weg gilt, der in dem Video vorgestellt wird, nicht für die Verwendung von Interfaces für den Zweck der Entkoppelung an sich.


delfiphan - Di 29.11.11 23:42

Der Code ist vermutlich nicht einfacher zu lesen, da die Abhängigkeiten praktisch nur in der Konfiguration (in einer Form oder anderen) definiert sind.

Ich würde jedoch behaupten, dass man bei gutem Languagesupport von Interfaces besseren Code schreibt. Mit besser mein ich mehr Separation of Concern, mehr Single Responsibility Principle und bessere Testability.

In Delphi habe ich die Erfahrung gemacht, dass man im Vergleich zu .NET einfach um eine Grössenordnung oder zwei weniger unit- und integrationstestet. Ich kann mir das nur mit der Umgebung, der Sprache und dem Framework erklären.

Von "Gefahren" wie "aus Versehen was gelöscht ohne zu merken" kann man nur sprechen, wenn man die Richtigkeit des Codes vor allem dadurch erkennt, dass der Code kompiliert... Das kann's ja nicht sein. Hätte man jetzt gute Tests (die man eben in einer guten Umgebung und Architektur eben relativ leicht schreibt), könnte sowas gar nicht passieren: In .NET Häusern wird häufig ein Gated-Check-In konfiguriert, sodass man nichts einchecken kann, das entweder nicht kompiliert oder irgend einen Test bricht.

Die Angst, an einer Stelle was zu ändern und an einer ganz anderen Stelle ein Problem zu kriegen, hat man vor allem dann, wenn man kein gutes Separation of Concern hat. Ohne Abstraktion z.B. über Interfaces ist die Versuchung eben viel grösser, harte Annahmen über eine abhängige Komponente zu machen.


jaenicke - Mi 30.11.11 11:59

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Von "Gefahren" wie "aus Versehen was gelöscht ohne zu merken" kann man nur sprechen, wenn man die Richtigkeit des Codes vor allem dadurch erkennt, dass der Code kompiliert... Das kann's ja nicht sein.
Schon, aber man kann nicht alles testen. Beispielsweise Hardware-, Netzwerk- oder öffentliche Internetschnittstellen wirst du nicht immer per Unittest erschlagen können. Und dann merkt man einen Fehler eben erst, wenn man bei einem Kunden ein Update macht, der dieses Feature auch benutzt.


delfiphan - Mi 30.11.11 19:00

Sowas kannst du überhaupt nicht unittesten. Das kannst du nur integrationstesten. Das ist zugegebenermassen etwas komplexer und aufwändiger.

Aber normalerweise sind die Libraries mit den Abhängigkeiten mit der Aussenwelt Off-the-Shelf-Software. Sowas musst du ja nicht nochmals selber testen. Der Punkt ist eben, dass dein Code nicht direkt auf die Implementation eines Netzwerkzugriffs geht sondern auf ein Interface. Dieses Interface ist im Testfall gemockt. Somit kannst du deinen gesamten Code sauber unittesten, ohne, dass jemals ein echter Netzwerkzugriff stattgefunden hat.

In einer regulierten Umgebung (z.B. medizinische Anwendung) kann und darf man eigentlich nichts dem Zufall überlassen. Da musst du jedes Requirement an Unittests, Unit-Integrationstests und Integrationstests tracen und beweisen, dass das Ding richtig tut, und dass das Ding das Richtige tut. Das ganze hat im Ernstfall auch juristische Relevanz. "Das kann ich nicht testen" gibt es da nicht, sonst kommt das ganze nicht auf den Markt ;)


baka0815 - Mo 23.01.12 12:30

Zum Thema ein Artikel von Nick Hodges [http://www.nickhodges.com/page/Why-You-Should-be-Using-Interfaces-and-not-Direct-References.aspx], den ich hier einmal unkommentiert verlinken möchte.


jaenicke - Mo 23.01.12 13:12

Ja, den hatte ich auch heute Morgen schon gelesen. Im Grunde ist das das gleiche wie im Video, nur in Schriftform.

Ich hatte mittlerweile auch ein wenig mit dem Konzept herumgespielt. Bisher hatte ich wenige positive Erlebnisse. Einerseits macht es das ganze ziemlich aufwendig. Andererseits fallen mir für bisher leicht machbare Zuordnungen von Strukturen keine adäquaten Möglichkeiten ein das nur mit Interfaces so einfach umzusetzen. Es geht zwar, aber es sieht nicht schön aus.

Im Moment hat sich nur der Codeumfang ca. verdoppelt und das Programm ist spürbar langsamer ohne dass ich bisher einen besonderen Mehrwert sehe. :nixweiss:

Naja, wenn ich mal Zeit habe, schreibe ich das ganze einfach mal auf. Vielleicht hat ja dann jemand ein paar schlaue Ideen wie man es besser machen kann...


delfiphan - Mo 23.01.12 23:02

Naja, ich kann mich nur wiederholen: In Delphi würde ich würde davon abraten. In Delphi mach ich das nie. In .NET mach ich das fast immer. Der Unterschied ist der schlechte Language und IDE Support für Interfaces in Delphi und Libraries für Dependency Injection.

Der Blogeintrag ist mässig gut und leider relativ einseitig. Als ob Interfaces die Welt retten könnten und in Delphi keine Probleme mit sich brächten. Ich habe das Gefühl, er hat grad die Interfaces entdeckt und ist noch ganz ausser sich. Nach dem vierten Satz in folgendem Stil musste ich schon etwas schmunzeln...
Zitat:
there is one bottom line reason why you should use interfaces in Delphi: They They provide a very thin – but very powerful -- abstraction to your code. That’s why.

Zitat:
A good developer codes against abstractions, and not implementations.

Zitat:
all the cool kids are doing interfaces, and you want to be part of the cool kid group, right?

Zitat:
And we all know that loosely coupled code is good. So interfaces help produce good code.


Eigentlich sollte man richtige und gute Gründe für etwas haben. Einfach so ein Prinzip anwenden, weil es "cool" ist, ist schlecht. Sonst passiert genau das, was jaenicke erzählt: Man hat etwas übertrieben gesprochen am Schluss doppelt so viel Code, der halb so schnell läuft und schwieriger zu verstehen ist -- und weiss nicht einmal, wofür.

In .NET ist für mich der Hauptgrund für die generelle Verwendung von Interfaces das Testen, zusammen mit einem guten Mock Framework ist das super. Was für mich Loosely Couple Code bringt ist aber vor allem Inversion of Contorl in Form von Dependency Injection. Ohne Garbage Collection ist Depdenency Injection mühsam, genauso die langsame Referenzzählung, und das ohne Support von Weak References und Events. Ausserdem gibt's keine guten und verbreiteten Mock oder DI Frameworks. In Delphi muss ich zu viele Kompromisse eingehen. Naja. Das gilt für mich mittlerweile eigentlich für die ganze Sprache ;)


jaenicke - Di 24.01.12 07:02

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
Ausserdem gibt's keine guten und verbreiteten Mock oder DI Frameworks.
Nick Hodges macht ja für dieses Werbung, worum es auch in dem Video ging:
http://code.google.com/p/delphi-spring-framework/


baka0815 - Di 24.01.12 14:02

@Jaenicke: Danke für den Link zum Spring4Delphi!

Ich würde gern mehr zur Referenzzählung von Interfaces wissen.
Was Nick Hodges da schreibt klingt nach: Nutze Interfaces und du brauchst dich nie wieder um die Laufzeit von Objekten kümmern.
Wenn man damit also wirklich (zuverlässig) auf try..finally verzichten könnte, wäre das doch eine feine Sache, oder?


jaenicke - Di 24.01.12 14:12

Theoretisch ja, aber praktisch möchte ich das gar nicht immer. In C# ärgere ich mich auch bisweilen über den Garbage Collector und in Java noch öfter. Bei relativ überschaubaren Tools ist das in der Tat sehr praktisch, aber wenn dann größere Speichermengen aufgrund des Scopes der Variable erst viel später freigegeben werden, ist das nicht so toll. Das ist vor allem bei Delphi ein Problem, da eben ein echter Garbage Collector fehlt.

Ich muss aber sagen, dass Interfaces in den aktuellen Delphiversionen sehr gut funktionieren. Das heißt man kann durchaus gut so arbeiten. Wenn man denn einen Vorteil daraus ziehen kann...


Martok - Di 24.01.12 17:38

Wer mal sehen möchte, wie schön Code mit Interfaces selbst in Delphi werden kann, darf sich gerne mal die Standard Interface Library [http://sourceforge.net/projects/sil/] angucken. Man merkt sehr, dass die Entwickler die positiven Neuerungen aus C# bzw. der CLR zurückklauen wollten.

Damit gearbeitet hab ich noch nicht, aber die Samples sehen sehr elegant aus - anders als man das von Delphi sonst kennt.


jaenicke - Di 24.01.12 19:52

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Damit gearbeitet hab ich noch nicht, aber die Samples sehen sehr elegant aus - anders als man das von Delphi sonst kennt.
So auf den ersten Blick sieht es ein wenig ähnlich wie das verlinkte Spring Framework aus, gerade im Hinblick auf das Registrieren von Interfaces. Aber ansonsten habe ich in den paar Beispielen, die ich jetzt angeschaut habe, nichts wirklich besonderes gesehen. So ähnlich sieht es auch mit Klassenmethoden und anonymen Methoden aus wie sie in den aktuellen Delphiversionen auch intern oft verwendet werden.

Hast du da vielleicht gerade ein Beispiel, das es sich lohnt näher anzuschauen? Das sind so viele... ;-)


delfiphan - Di 24.01.12 23:43

user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
Was Nick Hodges da schreibt klingt nach: Nutze Interfaces und du brauchst dich nie wieder um die Laufzeit von Objekten kümmern.

Das ist eine Illusion. Du kannst leicht zirkuläre Abhängigkeiten kriegen und so verhindern, dass Objekte jemals freigegeben werden und es kann passieren, dass Objekte zu früh freigegeben werden (z.B. bei Events, d.h. "Delegates"). Um das zu verhindern musst du in Delphi teilweise recht üble Hacks machen.

Einfaches Beispiel für ein Memory-Leak:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
type
  ITest = interface
  end;

  TTest = class(TInterfacedObject, ITest)
  private
    FTest: ITest;
  public
    constructor Create;
  end;

constructor TTest.Create;
begin
  FTest := Self;
end;


Ausserdem ist die Referenzzählung i.d.R. weniger effizient als ein GC, da bei jeder Zuweisung ein InterlockedIncrement gemacht werden muss.

Ein GC ist viel mächtiger. Ein GC kann in einem Wisch viele Objekte freigeben. Ein GC kann den Speicher defragmentieren. Ein GC kann verwaiste Gruppen erkennen, die sich gegenseitig zirkulär referenzieren und die ganze Gruppe freigeben. In C# hast du zudem schwache Referenzen und es ist nicht möglich, dass ein Objekt zu früh freigegeben wird.


baka0815 - Mi 25.01.12 12:44

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
Was Nick Hodges da schreibt klingt nach: Nutze Interfaces und du brauchst dich nie wieder um die Laufzeit von Objekten kümmern.

Das ist eine Illusion.

Das habe ich vermutet oder zumindest befürchtet.

In TInterfacedObject wird ja kein Free ausgeführt, sondern ein Destroy. Das heißt dann ja auch, dass ich Instanzen auf Interfaces oder zumindest wenn ich von TInterfacedObject erbe, nicht selbst freigeben darf, richtig?

Ich kann mich dann also gar nicht mehr selbst darum kümmern. Es wird somit nur ein Problem (ich muss mich selbst drum kümmern) durch ein anderes (die Objekte kümmern sich selber - schlecht) ersetzt, oder?


jaenicke - Mi 25.01.12 13:27

user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
Ich kann mich dann also gar nicht mehr selbst darum kümmern.
Richtig. Solange die Referenzzählung aktiv ist, darfst du nichts mehr selbst freigeben.

Und das ist genau was ich aber manchmal möchte und was mich an C# und Java immer wieder stört wie gesagt. So schön die automatische Freigabe auch ist, wenn man das nicht auch selbst steuern kann (GC bei Java und C#) oder nur durch dreckige Tricks (Interfaces in Delphi), gibt es immer wieder Situationen wo man sich so richtig schön verrenken muss, damit die Automatismen arbeiten wie man es möchte.


Martok - Mi 25.01.12 13:53

Ich muss mich grade ernsthaft verrenken, um eine Situation zu finden in der ich was selber freigeben will.
Wenn ich Speicher freigeben will, dann brauch ich den doch nicht mehr? Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum. Wenn ich die noch brauche, brauch ich die Daten dahinter aber auch noch... was programmierst du komisches? :P

Dass das in Delphi etwas kaputt ist stimmt aber. Wie eigentlich alles außer dem GUI-Designer. Aber ich schweife ab :P


baka0815 - Mi 25.01.12 14:07

Eigentlich mag ich das Konzept der GC ganz gerne und finde es teilweise nervig, dass ich mich in Delphi selbst drum kümmern muss.

Finde dann immer wieder Stolpersteine wie eine TStringList oder TObjectList die auf OwnsObjects=True gesetzt ist und ich somit versuche die Objekte doppelt freizugeben - was dann immer erst zu ewigen Suchen führt.
Dann sind da immer wieder stellen an denen man das try..finally doch vergessen hat und schon hat man ein Memory-Leak. Das kann passieren wenn man eben aus der Java- oder .NET-Welt kommt und die GC gewohnt ist.

Aber die Interface-Lösung von Delphi mit der internen Referenzzählung klingt dann ja auch nur erstmal nach 'ner guten Idee. Was mich auch stört ist, dass ich dann extra eine TInterfaceList brauche, mein Interface nicht auf eine Klasse casten kann und auch kein if (Intf is TObject) then machen kann, da das Interface ja kein TObject ist, auch wenn ich in dem konkreten Fall ja eine Instanz einer Klasse habe und wissen will, welche Klasse ich hier genau habe.
Kann man jetzt argumentieren, dass es sich dann um ein Designproblem meinerseits handelt, trotzdem finde ich das durchaus nervig...

@user profile iconjaenicke: Du kannst die GC in Java doch einfach manuell aufrufen - auch wenn man das nicht sollte.


jaenicke - Mi 25.01.12 14:46

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum.
Wenn es denn so wäre...
Ich hatte in einem Programm vor etwa einem halben Jahr in C# ca. 1,5 GiB RAM belegt, dann die Referenz auf diese Daten überschrieben und weitergemacht (in einer Schleife). Leider hat der GC aber nicht aufgeräumt, so dass nach wenigen Sekunden die Meldung kam, dass der Speicher voll sei.

Nach diversen Versuchen wie Auslagerung in eigene Methoden hatte ich es so gelöst, dass sich die Exe für jeden Durchlauf erneut selbst aufgerufen hat...

Dann habe ich es in Delphi gemacht und es lief sofort ohne Probleme und brauchte auch nur 1 GiB RAM maximal.

// EDIT:
user profile iconbaka0815 hat folgendes geschrieben Zum zitierten Posting springen:
mein Interface nicht auf eine Klasse casten kann und auch kein if (Intf is TObject) then machen kann, da das Interface ja kein TObject ist, auch wenn ich in dem konkreten Fall ja eine Instanz einer Klasse habe und wissen will, welche Klasse ich hier genau habe.
Doch, das geht. Ich weiß nicht ab welcher Delphiversion, aber mit den aktuellen Versionen (XE, XE2) auf jeden Fall. Ich schätze ab Delphi 2010, evtl. ab 2009.


delfiphan - Mi 25.01.12 19:13

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
Dann kann ich einfach die Referenz wegwerfen und der GC kümmert sich drum.
Wenn es denn so wäre...
Ich hatte in einem Programm vor etwa einem halben Jahr in C# ca. 1,5 GiB RAM belegt, dann die Referenz auf diese Daten überschrieben und weitergemacht (in einer Schleife). Leider hat der GC aber nicht aufgeräumt, so dass nach wenigen Sekunden die Meldung kam, dass der Speicher voll sei.

Das ist dann ziemlich sicher ein Bug in deinem C# Programm. Der GC in .NET ist nämlich ganz schön fleissig.

Du musst vor allem bei Events aufpassen. Denn Delegates, die man bei Events braucht, enthalten neben dem Methodenpointer auch eine starke Referenz auf das Objekt. In Delphi würdest du bei einem solchen Bug zwar den Speicher rechtzeitig freibekommen, würdest aber irgendwann mal eine AccessViolation kriegen. In .NET bleibt das Objekt halt am leben. Gibt aber gute Tools, die den ganzen Speicherbaum schön graphisch anzeigen können.

Wenn's was explizig zum Aufräumen gibt, verwende IDisposable. Dann hilft dir der Compiler bzw. FxCop auch immer schön, wenn du vergisst, aufzuräumen.


baka0815 - Mo 30.01.12 17:04

Sollte man in Delphi dann statt Interfaces abstrakte Klassen verwenden?
Dann muss ich mich zwar selber um den Speicher kümmern, habe aber die damit verbundenen Nachteile nicht.

Oder haben Abstrakte Klassen andere Nachteile - außer dass man diese instantiieren kann?


delfiphan - Mo 30.01.12 18:54

Eine abstrakte Basisklasse geht natürlich ein bisschen in die gleiche Richtung. Aber es gibt's keine Mehrfachvererbung, daher muss zuoberst in der Hierarchie immer diese abstrakte Klasse sein. Ein Interface kann man einfach an eine bestehende Klasse anhängen.